merge release test changes and preserve local frontend updates
This commit is contained in:
@@ -364,6 +364,15 @@ export async function getLastMileOrder(orderId: string) {
|
||||
return unwrapApiResponse(response)
|
||||
}
|
||||
|
||||
export async function reviewReturnOrder(returnNo: string, customerId: string, decision: 'APPROVE' | 'REJECT', remark?: string) {
|
||||
const response = await overseasHttp.post<ApiEnvelope<unknown>, ApiEnvelope<unknown>>(
|
||||
`/platform/v1/last-leg/return-orders/${encodeURIComponent(returnNo)}/review`,
|
||||
{ decision, remark: remark?.trim() || undefined },
|
||||
{ headers: { 'X-Customer-Id': customerId } },
|
||||
)
|
||||
return unwrapApiResponse(response)
|
||||
}
|
||||
|
||||
export async function downloadLastMileOrders(query: Partial<LastMileOrderQuery>) {
|
||||
const { page: _page, size: _size, ...filters } = query
|
||||
const params = Object.fromEntries(
|
||||
|
||||
@@ -98,6 +98,7 @@ export interface RelabelItemDto {
|
||||
cartonMark?: string | null
|
||||
fbaCartonMark?: string | null
|
||||
destinationWarehouseId?: string | null
|
||||
destinationFbaWarehouseCode?: string | null
|
||||
}
|
||||
|
||||
export interface RelabelHistoryDto {
|
||||
|
||||
@@ -15,10 +15,12 @@ const orderTypeLabels: Record<string, string> = {
|
||||
|
||||
const statusLabels: Record<string, string> = {
|
||||
PENDING_REVIEW: '待审核',
|
||||
PENDING_RECEIPT: '待签收入库',
|
||||
PARTIALLY_RECEIVED: '部分入库',
|
||||
INBOUND_COMPLETED: '全部入库',
|
||||
WAIT_PDA_RECEIVING: '入库测量中',
|
||||
INBOUND_MEASURING: '入库测量中',
|
||||
WAIT_CUSTOMER_CONFIRMATION: '待客户确认实测',
|
||||
INBOUND_COMPLETED: '入库完成',
|
||||
APPROVED: '审核通过',
|
||||
PENDING_ASSIGNMENT: '待分配',
|
||||
WAIT_RELABEL: '待换标',
|
||||
@@ -27,7 +29,6 @@ const statusLabels: Record<string, string> = {
|
||||
WAIT_OUTBOUND: '待出库',
|
||||
ALLOCATED: '已分配库存',
|
||||
OUTBOUNDED: '已出库',
|
||||
PARTIALLY_RECEIVED: '部分收货',
|
||||
RECEIVED: '已收货',
|
||||
IN_TRANSIT: '运输中',
|
||||
DESTINATION_ASSIGNED: '已分配目的仓',
|
||||
@@ -35,6 +36,7 @@ const statusLabels: Record<string, string> = {
|
||||
PENDING_PROCESSING: '待处理',
|
||||
PROCESSING: '处理中',
|
||||
COMPLETED: '已完成',
|
||||
REJECTED: '已驳回',
|
||||
CANCELLED: '已取消',
|
||||
}
|
||||
|
||||
@@ -145,6 +147,7 @@ export function toLastMileOrderListItem(dto: LastMileOrderSummaryDto): LastMileO
|
||||
customerId: String(dto.customerId),
|
||||
sourceContainerBookingId: String(dto.sourceContainerBookingId ?? '').trim(),
|
||||
orderNo: lastMileOrderReference(dto.orderNo),
|
||||
sourceOrderNo: lastMileOrderReference(dto.sourceOrderNo, ''),
|
||||
orderTypeCode: String(dto.orderType ?? '').trim(),
|
||||
currentStatusCode: String(dto.currentStatus ?? '').trim(),
|
||||
warning: dto.abnormal ? '异常' : '—',
|
||||
|
||||
@@ -15,7 +15,7 @@ import LoadErrorState from '@/shared/components/LoadErrorState.vue'
|
||||
import OperationErrorToast from '@/shared/components/OperationErrorToast.vue'
|
||||
import QueryToolbar, { type QueryField, type QueryModel } from '@/shared/components/QueryToolbar.vue'
|
||||
import RowActions, { type RowActionItem } from '@/shared/components/RowActions.vue'
|
||||
import { changeContainerReceivingWarehouse, convertLastMileContainerToInboundPlans, createManualInboundPlan, downloadLastMileOrders, getContainerInboundPlanPreview, getContainerPlanProgress, getLastMileOrderManualNodes, listContainerPlanProgress, listLastMileOrders, transferLastMileOrders, updateLastMileOrderHold, updateLastMileOrderManualNodes, type ContainerInboundPlanPreviewDto, type ContainerInboundPlanPreviewGroupDto, type ContainerInboundPlanPreviewOrderDto, type ContainerPlanProgressDetailDto, type ContainerPlanProgressSummaryDto, type ManualNodeCode } from '../api/lastMileOrders'
|
||||
import { changeContainerReceivingWarehouse, convertLastMileContainerToInboundPlans, createManualInboundPlan, downloadLastMileOrders, getContainerInboundPlanPreview, getContainerPlanProgress, getLastMileOrderManualNodes, listContainerPlanProgress, listLastMileOrders, reviewReturnOrder, transferLastMileOrders, updateLastMileOrderHold, updateLastMileOrderManualNodes, type ContainerInboundPlanPreviewDto, type ContainerInboundPlanPreviewGroupDto, type ContainerInboundPlanPreviewOrderDto, type ContainerPlanProgressDetailDto, type ContainerPlanProgressSummaryDto, type ManualNodeCode } from '../api/lastMileOrders'
|
||||
import OrderReferenceText from '../components/OrderReferenceText.vue'
|
||||
import WarehouseTransferReviewDialog from '../components/WarehouseTransferReviewDialog.vue'
|
||||
import { confirmRelabelCompletion, getRelabelReviewTask, returnRelabelForRework } from '../api/relabelOrders'
|
||||
@@ -440,6 +440,11 @@ async function submitReceivingWarehouseChange() {
|
||||
}
|
||||
}
|
||||
function onSelectionChange(selection: object[]) { selectedRows.value = selection as LastMileOrderListItem[] }
|
||||
function isRejectedReturn(source: object) {
|
||||
const row = source as LastMileOrderListItem
|
||||
return row.orderTypeCode === 'RETURN_RELABEL' && row.currentStatusCode === 'REJECTED'
|
||||
}
|
||||
function hasSelectedRejectedReturn() { return selectedRows.value.some(isRejectedReturn) }
|
||||
async function loadTransferWarehouseOptions() {
|
||||
transferWarehouseLoading.value = true
|
||||
transferWarehouseError.value = null
|
||||
@@ -461,6 +466,7 @@ function selectTransferWarehouse(warehouseId: string) {
|
||||
}
|
||||
function openTransfer() {
|
||||
if (!selectedRows.value.length) { ElMessage.warning('请至少选择 1 条尾程订单'); return }
|
||||
if (hasSelectedRejectedReturn()) { ElMessage.warning('已驳回的退货预报只能查看详情'); return }
|
||||
Object.assign(transferForm, { warehouseId: '', warehouseCode: '', warehouseName: '', remark: '' })
|
||||
transferWarehouseOptions.value = []
|
||||
transferWarehouseError.value = null
|
||||
@@ -493,6 +499,8 @@ function idempotencyKey(prefix: string) {
|
||||
function openInboundPlan(source?: object) {
|
||||
const target = source ? source as LastMileOrderListItem : (selectedRows.value.length === 1 ? selectedRows.value[0] : null)
|
||||
if (!target) { ElMessage.warning('生成入库计划时请选择 1 条尾程订单'); return }
|
||||
if (isRejectedReturn(target)) { ElMessage.warning('已驳回的退货预报只能查看详情'); return }
|
||||
if (target.detained) { ElMessage.warning('订单处于暂扣状态,解除暂扣后才能生成入库计划'); return }
|
||||
actionTarget.value = target
|
||||
const volumeMinimum = typeof target.volume === 'number' && target.volume > 0 ? Math.ceil(target.volume / 2) : 1
|
||||
inboundPlanMinimumPalletCount.value = Math.max(1, volumeMinimum,
|
||||
@@ -776,11 +784,44 @@ watch(containerConvertOpen, (open) => {
|
||||
containerConversionIdempotencyKey = ''
|
||||
})
|
||||
|
||||
function rowActionCount(source: object) {
|
||||
const row = source as LastMileOrderListItem
|
||||
if (isRejectedReturn(row)) return 1
|
||||
const count = 1
|
||||
+ Number(access.can(permission.warehouseTransferApprove) && row.orderTypeCode === 'WAREHOUSE_TRANSFER' && row.currentStatusCode === 'PENDING_REVIEW')
|
||||
+ Number(access.can(permission.returnOrderReview) && row.orderTypeCode === 'RETURN_RELABEL' && row.currentStatusCode === 'PENDING_REVIEW')
|
||||
+ Number(access.can(permission.inboundOrderCreate))
|
||||
+ (access.can(permission.lastMileOrderTransfer) ? 2 : 0)
|
||||
+ Number(access.can(permission.relabelOrderStatus) && Boolean(row.relabelOrderNo) && canConfirmRelabel(row))
|
||||
+ Number(access.can(permission.relabelOrderStatus) && Boolean(row.relabelOrderNo) && canReworkRelabel(row))
|
||||
return hasRelabelActions(row) ? Math.max(4, count) : count
|
||||
}
|
||||
async function reviewReturn(source: object) {
|
||||
const row = source as LastMileOrderListItem
|
||||
const returnNo = row.sourceOrderNo
|
||||
if (!returnNo || !row.customerId) return
|
||||
try {
|
||||
await ElMessageBox.confirm('审核通过后,仓库才可以签收这张退货预报。', '退货预报审核', { confirmButtonText: '审核通过', cancelButtonText: '驳回', distinguishCancelAndClose: true })
|
||||
await reviewReturnOrder(returnNo, row.customerId, 'APPROVE')
|
||||
ElMessage.success('退货预报已审核通过')
|
||||
await load()
|
||||
} catch (error) {
|
||||
if (error === 'cancel') {
|
||||
try {
|
||||
const { value } = await ElMessageBox.prompt('请填写驳回原因', '驳回退货预报', { inputType: 'textarea', inputValidator: (input) => Boolean(input?.trim()) || '请填写驳回原因', confirmButtonText: '确认驳回', cancelButtonText: '取消' })
|
||||
await reviewReturnOrder(returnNo, row.customerId, 'REJECT', value)
|
||||
ElMessage.success('退货预报已驳回')
|
||||
await load()
|
||||
} catch (rejectError) { if (rejectError !== 'cancel' && rejectError !== 'close') ElMessage.error(getApiErrorDetails(rejectError, '退货预报审核失败').message) }
|
||||
} else if (error !== 'close') ElMessage.error(getApiErrorDetails(error, '退货预报审核失败').message)
|
||||
}
|
||||
}
|
||||
function canConfirmRelabel(row: { relabelStatusCode?: string }) { return row.relabelStatusCode === 'CUSTOMER_CONFIRM_PENDING' }
|
||||
function canReworkRelabel(row: { relabelStatusCode?: string }) { return ['CUSTOMER_CONFIRM_PENDING', 'PROCESSING'].includes(row.relabelStatusCode ?? '') }
|
||||
function lastMileRowActions(row: LastMileOrderListItem): RowActionItem[] {
|
||||
return [
|
||||
{ key: 'detail', label: '查看', priority: 500 },
|
||||
{ key: 'review-return', label: '审核', priority: 460, tone: 'warning', visible: access.can(permission.returnOrderReview) && row.orderTypeCode === 'RETURN_RELABEL' && row.currentStatusCode === 'PENDING_REVIEW' },
|
||||
{ key: 'review', label: '审核', priority: 450, tone: 'warning', visible: access.can(permission.warehouseTransferApprove) && row.orderTypeCode === 'WAREHOUSE_TRANSFER' && row.currentStatusCode === 'PENDING_REVIEW' },
|
||||
{ key: 'inbound-plan', label: '入库计划', priority: 400, visible: access.can(permission.inboundOrderCreate) },
|
||||
{ key: 'hold', label: row.detained ? '解除暂扣' : '暂扣订单', priority: 300, tone: 'warning', visible: access.can(permission.lastMileOrderTransfer), disabled: !row.detained && row.currentStatusCode !== 'INBOUND_COMPLETED' },
|
||||
@@ -791,6 +832,7 @@ function lastMileRowActions(row: LastMileOrderListItem): RowActionItem[] {
|
||||
}
|
||||
function handleLastMileRowAction(command: string, row: LastMileOrderListItem) {
|
||||
if (command === 'detail') openDetail(row)
|
||||
else if (command === 'review-return') void reviewReturn(row)
|
||||
else if (command === 'review') openTransferReview(row)
|
||||
else if (command === 'inbound-plan') openInboundPlan(row)
|
||||
else if (command === 'hold') openHold(row)
|
||||
@@ -890,7 +932,7 @@ onMounted(() => { void load() })
|
||||
</div>
|
||||
</section>
|
||||
<section v-else-if="!loadError" class="surface-panel table-panel"><DataTable v-model:page="page" v-model:page-size="pageSize" :data="rows" :columns="columns" :loading="loading" :total="total" preference-key="overseas-last-mile-orders" row-key="id" empty-text="暂无尾程订单" @selection-change="onSelectionChange" @update:page="load()" @update:page-size="page = 1; load()">
|
||||
<template #toolbar-actions><el-button v-if="access.can(permission.lastMileOrderExport)" plain :loading="exportLoading" @click="exportOrders"><Download :size="16" />导出订单</el-button><el-button v-if="access.can(permission.lastMileOrderTransfer)" plain :disabled="!selectedRows.length || actionLoading" @click="openTransfer">转仓</el-button><el-button v-if="access.can(permission.inboundOrderCreate)" type="primary" plain :disabled="selectedRows.length !== 1 || actionLoading" @click="openInboundPlan()">生成入库计划</el-button><el-button v-if="statusTab === '待分配' && access.can(permission.inboundOrderCreate)" type="primary" :disabled="actionLoading" @click="openContainerConversion">按柜批量生成</el-button></template>
|
||||
<template #toolbar-actions><el-button v-if="access.can(permission.lastMileOrderExport)" plain :loading="exportLoading" @click="exportOrders"><Download :size="16" />导出订单</el-button><el-button v-if="access.can(permission.lastMileOrderTransfer)" plain :disabled="!selectedRows.length || hasSelectedRejectedReturn() || actionLoading" @click="openTransfer">转仓</el-button><el-button v-if="access.can(permission.inboundOrderCreate)" type="primary" plain :disabled="selectedRows.length !== 1 || hasSelectedRejectedReturn() || actionLoading" @click="openInboundPlan()">生成入库计划</el-button><el-button v-if="statusTab === '待分配' && access.can(permission.inboundOrderCreate)" type="primary" :disabled="actionLoading" @click="openContainerConversion">按柜批量生成</el-button></template>
|
||||
<template #actions="{ row }"><RowActions :actions="lastMileRowActions(row as LastMileOrderListItem)" :more-label="`更多尾程订单操作 · ${(row as LastMileOrderListItem).orderNo || '当前记录'}`" @action="handleLastMileRowAction($event, row as LastMileOrderListItem)" /></template>
|
||||
<template #orderNo="{ row }"><OrderReferenceText :value="String(row.orderNo || '')" copyable /></template>
|
||||
<template #cartonDifference="{ row }"><span :class="{ 'package-difference--nonzero': typeof row.cartonDifference === 'number' && row.cartonDifference !== 0 }">{{ packageDifferenceText(row.cartonDifference) }}</span></template>
|
||||
|
||||
@@ -13,4 +13,10 @@ describe('RelabelOrderDetailView', () => {
|
||||
expect(source).toContain('text(item.fbaCartonMark)')
|
||||
expect(source).not.toContain("{ title: '箱唛换标信息', fields:")
|
||||
})
|
||||
|
||||
it('shows the review state and customer-facing return order and FBA warehouse codes', () => {
|
||||
expect(source).toContain("PENDING_REVIEW: '待审核'")
|
||||
expect(source).toContain('value?.application.customerOrderNo || value?.application.lastlegOrderNo')
|
||||
expect(source).toContain('item.destinationFbaWarehouseCode || item.destinationWarehouseId')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -46,9 +46,16 @@ const groups = [
|
||||
]
|
||||
function text(value: unknown) { return String(value ?? '').trim() || '—' }
|
||||
function status(value: unknown) {
|
||||
if (value === 'CUSTOMER_CONFIRM_PENDING') return '待客户确认'
|
||||
if (value === 'PROCESSING') return '处理中'
|
||||
return ['READY_FOR_OUTBOUND', 'COMPLETED'].includes(String(value || '')) ? '换标完成' : '待处理'
|
||||
return ({
|
||||
PENDING_REVIEW: '待审核',
|
||||
PENDING_PROCESSING: '待处理',
|
||||
PROCESSING: '处理中',
|
||||
CUSTOMER_CONFIRM_PENDING: '待客户确认',
|
||||
READY_FOR_OUTBOUND: '换标完成',
|
||||
COMPLETED: '换标完成',
|
||||
REJECTED: '已驳回',
|
||||
CANCELLED: '已取消',
|
||||
} as Record<string, string>)[String(value || '')] || text(value)
|
||||
}
|
||||
function walletStatus(value: unknown) { return ({ FREEZE_PENDING: '冻结中', FROZEN: '已冻结', SETTLE_PENDING: '结算中', SETTLED: '已结算', RELEASE_PENDING: '释放中', RELEASED: '已释放', FREEZE_FAILED: '冻结失败', SETTLE_FAILED: '结算失败', RELEASE_FAILED: '释放失败' } as Record<string,string>)[String(value || '')] || text(value) }
|
||||
const referenceValue = computed(() => text(detail.value?.application.relabelNo || '换标单号待补充'))
|
||||
@@ -57,7 +64,7 @@ const fieldValues = computed<Record<string, string | number>>(() => {
|
||||
const items = value?.items || []
|
||||
return {
|
||||
换标单号: text(value?.application.relabelNo),
|
||||
关联订单: text(value?.application.lastlegOrderNo || value?.application.customerOrderNo),
|
||||
关联订单: text(value?.application.customerOrderNo || value?.application.lastlegOrderNo),
|
||||
状态: status(value?.application.status),
|
||||
资金状态: walletStatus(value?.application.walletStatus),
|
||||
创建时间: formatOverseasDateTime(value?.application.createdAt),
|
||||
@@ -117,7 +124,7 @@ async function previewCompletionPhoto(fileId: string) {
|
||||
<table class="density-table">
|
||||
<thead><tr><th>我方箱唛</th><th>FBA 箱唛</th><th>商品 SKU</th><th>中文品名</th><th>FBA 货件编号</th><th>换标新 SKU</th><th>目的仓</th><th>明细PDF</th></tr></thead>
|
||||
<tbody>
|
||||
<tr v-for="item in detail?.items || []" :key="item.id"><td class="mark-code">{{ text(item.cartonMark) }}</td><td class="mark-code">{{ text(item.fbaCartonMark) }}</td><td>{{ text(item.skuCode) }}</td><td>{{ text(item.productNameZh) }}</td><td>{{ text(item.shipmentNo) }}</td><td>{{ text(item.newSkuCode) }}</td><td>{{ text(item.destinationWarehouseId) }}</td><td><span v-if="item.relabelFileName" class="document-actions density-actions"><strong>{{ item.relabelFileName }}</strong><el-button class="density-action" data-tone="neutral" size="small" @click="previewPdf(item.relabelFileId, item.relabelFileName, 'ITEM', item.id)">预览</el-button></span><label v-else class="inline-file-picker"><FileUp :size="14" />上传<input type="file" accept="application/pdf,.pdf" :disabled="uploading" @change="uploadPdf($event, 'ITEM', item.id)" /></label></td></tr>
|
||||
<tr v-for="item in detail?.items || []" :key="item.id"><td class="mark-code">{{ text(item.cartonMark) }}</td><td class="mark-code">{{ text(item.fbaCartonMark) }}</td><td>{{ text(item.skuCode) }}</td><td>{{ text(item.productNameZh) }}</td><td>{{ text(item.shipmentNo) }}</td><td>{{ text(item.newSkuCode) }}</td><td>{{ text(item.destinationFbaWarehouseCode || item.destinationWarehouseId) }}</td><td><span v-if="item.relabelFileName" class="document-actions density-actions"><strong>{{ item.relabelFileName }}</strong><el-button class="density-action" data-tone="neutral" size="small" @click="previewPdf(item.relabelFileId, item.relabelFileName, 'ITEM', item.id)">预览</el-button></span><label v-else class="inline-file-picker"><FileUp :size="14" />上传<input type="file" accept="application/pdf,.pdf" :disabled="uploading" @change="uploadPdf($event, 'ITEM', item.id)" /></label></td></tr>
|
||||
<tr v-if="!detail?.items.length"><td class="empty-cell" colspan="8">暂无箱唛换标信息</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -109,19 +109,27 @@ describe('RelabelOrdersView', () => {
|
||||
}))
|
||||
})
|
||||
|
||||
it('offers only backend-allowed audit transitions', async () => {
|
||||
it('hides the audit action after approval', async () => {
|
||||
vi.mocked(listRelabelOrders).mockResolvedValueOnce({
|
||||
records: [{ id: '1', relabelNo: 'RL-1', customerOrderNo: 'CO-1', skuCodes: 'SKU-1', totalPackageCount: 2, status: 'PENDING_PROCESSING' }],
|
||||
page: 1, size: 10, total: 1, pages: 1,
|
||||
})
|
||||
const wrapper = mount(RelabelOrdersView, { attachTo: document.body, global: { plugins: [ElementPlus] } })
|
||||
await flushPromises()
|
||||
await wrapper.findAll('button').find((button) => button.text().includes('审核'))!.trigger('click')
|
||||
await flushPromises()
|
||||
expect(wrapper.findAll('button').some((button) => button.text().trim() === '审核')).toBe(false)
|
||||
})
|
||||
|
||||
const labels = formItem(wrapper, '目标状态').findAllComponents({ name: 'ElOption' }).map((option) => option.props('label'))
|
||||
expect(labels).toEqual(expect.arrayContaining(['处理中', '已驳回', '已取消']))
|
||||
expect(labels).not.toContain('已完成')
|
||||
it('shows the audit action only while pending review', async () => {
|
||||
vi.mocked(listRelabelOrders).mockResolvedValueOnce({
|
||||
records: [{ id: '1', relabelNo: 'RL-1', customerOrderNo: 'CO-1', skuCodes: 'SKU-1', totalPackageCount: 2, status: 'PENDING_REVIEW' }],
|
||||
page: 1, size: 10, total: 1, pages: 1,
|
||||
})
|
||||
const wrapper = mount(RelabelOrdersView, { attachTo: document.body, global: { plugins: [ElementPlus] } })
|
||||
await flushPromises()
|
||||
await wrapper.findAll('button').find((button) => button.text().trim() === '审核')!.trigger('click')
|
||||
await flushPromises()
|
||||
const labels = formItem(wrapper, '审核动作').findAllComponents({ name: 'ElOption' }).map((option) => option.props('label'))
|
||||
expect(labels).toEqual(['审核通过', '已驳回'])
|
||||
})
|
||||
|
||||
it('passes the relabel order number search to the backend', async () => {
|
||||
|
||||
@@ -35,7 +35,7 @@ const filters = ref<QueryModel>({ relabelNo: '', sku: '', status: '' })
|
||||
const fields = computed<QueryField[]>(() => [
|
||||
{ key: 'relabelNo', type: 'input', label: '换标单号', placeholder: '请输入换标单号', width: 220 },
|
||||
{ key: 'sku', type: 'input', label: '商品SKU', placeholder: '请输入商品SKU', width: 180 },
|
||||
{ key: 'status', type: 'select', label: '状态', placeholder: '全部状态', width: 160, options: [{ label: '待处理', value: 'PENDING_PROCESSING' }, { label: '处理中', value: 'PROCESSING' }, { label: '换标完成', value: 'COMPLETED' }] },
|
||||
{ key: 'status', type: 'select', label: '状态', placeholder: '全部状态', width: 160, options: [{ label: '待审核', value: 'PENDING_REVIEW' }, { label: '待处理', value: 'PENDING_PROCESSING' }, { label: '处理中', value: 'PROCESSING' }, { label: '换标完成', value: 'COMPLETED' }] },
|
||||
])
|
||||
const columns: DataTableColumn[] = [
|
||||
{ key: 'actions', label: '操作', width: 180, fixed: 'left', slotName: 'actions' },
|
||||
@@ -58,6 +58,7 @@ const editSourceStatus = ref('')
|
||||
const form = reactive({ orderNo: '', customerId: '', relatedOrderNo: '', sku: '', productName: '', cartons: undefined as number | undefined, budgetTotal: undefined as number | undefined, status: 'PENDING_PROCESSING', labelRequirement: '', relabelCost: undefined as number | undefined, remark: '', warehouseId: '', labelDeadline: '', contactName: '', contactPhone: '', shipmentNo: '', newSkuCode: '' })
|
||||
const createIdempotencyKey = ref('')
|
||||
const allowedStatusOptions = computed(() => {
|
||||
if (editSourceStatus.value === 'PENDING_REVIEW') return ['PENDING_PROCESSING', 'REJECTED']
|
||||
if (editSourceStatus.value === 'PENDING_PROCESSING') return ['PROCESSING', 'REJECTED', 'CANCELLED']
|
||||
if (editSourceStatus.value === 'PROCESSING') return ['COMPLETED', 'REJECTED', 'CANCELLED']
|
||||
return []
|
||||
@@ -127,6 +128,7 @@ async function submitForm() {
|
||||
ElMessage.success('换标单已创建')
|
||||
} else {
|
||||
if (!allowedStatusOptions.value.includes(form.status)) { ElMessage.warning('当前状态没有可提交的审核流转'); return }
|
||||
if (form.status === 'REJECTED' && !form.remark.trim()) { ElMessage.warning('审核驳回请填写原因'); return }
|
||||
submitting.value = true
|
||||
await changeRelabelOrderStatus(form.orderNo, form.status, form.remark || undefined)
|
||||
ElMessage.success('状态已更新')
|
||||
@@ -148,6 +150,7 @@ function relabelStatus(value: unknown) {
|
||||
}
|
||||
function relabelAuditStatusLabel(value: string) {
|
||||
return ({
|
||||
PENDING_PROCESSING: '审核通过',
|
||||
PROCESSING: '处理中',
|
||||
REJECTED: '已驳回',
|
||||
CANCELLED: '已取消',
|
||||
@@ -155,13 +158,13 @@ function relabelAuditStatusLabel(value: string) {
|
||||
} as Record<string, string>)[value] || relabelStatus(value)
|
||||
}
|
||||
function relabelStatusCode(value: unknown) {
|
||||
const codes: Record<string, string> = { 待处理: 'PENDING_PROCESSING', 处理中: 'PROCESSING', 换标完成: 'COMPLETED' }
|
||||
const codes: Record<string, string> = { 待审核: 'PENDING_REVIEW', 待处理: 'PENDING_PROCESSING', 处理中: 'PROCESSING', 换标完成: 'COMPLETED' }
|
||||
return codes[String(value || '')] || String(value || 'PENDING_PROCESSING')
|
||||
}
|
||||
function walletStatus(value: unknown) { return ({ FREEZE_PENDING: '冻结中', FROZEN: '已冻结', SETTLE_PENDING: '结算中', SETTLED: '已结算', RELEASE_PENDING: '释放中', RELEASED: '已释放', FREEZE_FAILED: '冻结失败', SETTLE_FAILED: '结算失败', RELEASE_FAILED: '释放失败' } as Record<string,string>)[String(value || '')] || String(value || '—') }
|
||||
function canAudit(source: object) {
|
||||
const row = source as RelabelOrderListItem
|
||||
return ['PENDING_PROCESSING', 'PROCESSING'].includes(row.rawStatus || relabelStatusCode(row.status))
|
||||
return (row.rawStatus || relabelStatusCode(row.status)) === 'PENDING_REVIEW'
|
||||
}
|
||||
async function load(model: QueryModel = filters.value) {
|
||||
Object.assign(filters.value, model)
|
||||
@@ -205,7 +208,7 @@ watch(dialogOpen, (open) => { if (!open) createIdempotencyKey.value = '' })
|
||||
<el-col v-if="dialogMode === 'create'" :span="12"><el-form-item label="截止时间" required><el-date-picker v-model="form.labelDeadline" type="datetime" value-format="YYYY-MM-DDTHH:mm:ss" placeholder="请选择截止时间" /></el-form-item></el-col>
|
||||
<el-col v-if="dialogMode === 'create'" :span="12"><el-form-item label="联系人" required><el-input v-model="form.contactName" placeholder="请输入联系人" /></el-form-item></el-col>
|
||||
<el-col v-if="dialogMode === 'create'" :span="12"><el-form-item label="联系电话" required><el-input v-model="form.contactPhone" placeholder="请输入联系电话" /></el-form-item></el-col>
|
||||
<el-col v-if="dialogMode === 'edit'" :span="12"><el-form-item label="目标状态"><el-select v-model="form.status" placeholder="请选择目标状态"><el-option v-for="value in allowedStatusOptions" :key="value" :label="relabelAuditStatusLabel(value)" :value="value" /></el-select></el-form-item></el-col>
|
||||
<el-col v-if="dialogMode === 'edit'" :span="12"><el-form-item label="审核动作"><el-select v-model="form.status" placeholder="请选择审核动作"><el-option v-for="value in allowedStatusOptions" :key="value" :label="relabelAuditStatusLabel(value)" :value="value" /></el-select></el-form-item></el-col>
|
||||
</el-row><h3>作业要求</h3><el-row :gutter="16">
|
||||
<el-col :span="12"><el-form-item label="贴标要求" required><el-select v-model="form.labelRequirement" :disabled="dialogMode === 'edit'" placeholder="请选择贴标要求"><el-option v-for="value in ['换箱唛', '换SKU标', '换箱唛和SKU标']" :key="value" :label="value" :value="value" /></el-select></el-form-item></el-col>
|
||||
<el-col :span="12"><el-form-item label="货件号" required><el-input v-model="form.shipmentNo" :disabled="dialogMode === 'edit'" placeholder="请输入货件号" /></el-form-item></el-col>
|
||||
|
||||
@@ -28,6 +28,7 @@ export const overseasWarehousePermissions = {
|
||||
inventoryEdit: 'platform:overseas-warehouse:inventory:edit',
|
||||
inventoryAdjust: 'platform:overseas-warehouse:inventory:adjust',
|
||||
returnInventoryList: 'platform:overseas-warehouse:return-inventory:list',
|
||||
returnOrderReview: 'platform:overseas-warehouse:return-inventory:list',
|
||||
returnCartonsList: 'platform:overseas-warehouse:return-cartons:list',
|
||||
relabelOrderList: 'platform:overseas-warehouse:relabel-order:list',
|
||||
relabelOrderCreate: 'platform:overseas-warehouse:relabel-order:create',
|
||||
|
||||
@@ -8,6 +8,7 @@ export interface LastMileOrderListItem {
|
||||
customerId: string
|
||||
sourceContainerBookingId: string
|
||||
orderNo: string
|
||||
sourceOrderNo: string
|
||||
orderTypeCode: string
|
||||
currentStatusCode: string
|
||||
warning: string
|
||||
|
||||
Reference in New Issue
Block a user