优化提交
This commit is contained in:
@@ -383,6 +383,15 @@ export async function reviewDirectRelabelOrder(orderId: string, customerId: stri
|
|||||||
return unwrapApiResponse(response)
|
return unwrapApiResponse(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function reviewCargoDiscardOrder(discardNo: string, customerId: string, decision: 'APPROVE' | 'REJECT', remark?: string) {
|
||||||
|
const response = await overseasHttp.post<ApiEnvelope<unknown>, ApiEnvelope<unknown>>(
|
||||||
|
`/platform/v1/last-leg/cargo-discards/${encodeURIComponent(discardNo)}/review`,
|
||||||
|
{ decision, remark: remark?.trim() || undefined },
|
||||||
|
{ params: { customerId } },
|
||||||
|
)
|
||||||
|
return unwrapApiResponse(response)
|
||||||
|
}
|
||||||
|
|
||||||
export async function downloadLastMileOrders(query: Partial<LastMileOrderQuery>) {
|
export async function downloadLastMileOrders(query: Partial<LastMileOrderQuery>) {
|
||||||
const { page: _page, size: _size, ...filters } = query
|
const { page: _page, size: _size, ...filters } = query
|
||||||
const params = Object.fromEntries(
|
const params = Object.fromEntries(
|
||||||
|
|||||||
@@ -9,6 +9,12 @@ export interface RelabelOrderQuery {
|
|||||||
relabelNo?: string
|
relabelNo?: string
|
||||||
skuCode?: string
|
skuCode?: string
|
||||||
status?: string
|
status?: string
|
||||||
|
reviewedFrom?: string
|
||||||
|
reviewedTo?: string
|
||||||
|
measuredFrom?: string
|
||||||
|
measuredTo?: string
|
||||||
|
outboundFrom?: string
|
||||||
|
outboundTo?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreateRelabelItemPayload {
|
export interface CreateRelabelItemPayload {
|
||||||
@@ -82,6 +88,9 @@ export interface RelabelSummaryDto {
|
|||||||
customerConfirmedAt?: string | null
|
customerConfirmedAt?: string | null
|
||||||
reviewChannel?: 'TAIL_ORDER' | 'RELABEL_ORDER' | null
|
reviewChannel?: 'TAIL_ORDER' | 'RELABEL_ORDER' | null
|
||||||
reviewRemark?: string | null
|
reviewRemark?: string | null
|
||||||
|
reviewedAt?: string | null
|
||||||
|
measuredAt?: string | null
|
||||||
|
outboundAt?: string | null
|
||||||
createdAt?: string | null
|
createdAt?: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,12 @@ export interface WarehouseTransferQuery {
|
|||||||
fbaWarehouseCode?: string
|
fbaWarehouseCode?: string
|
||||||
status?: string
|
status?: string
|
||||||
needRelabel?: boolean
|
needRelabel?: boolean
|
||||||
|
reviewedFrom?: string
|
||||||
|
reviewedTo?: string
|
||||||
|
measuredFrom?: string
|
||||||
|
measuredTo?: string
|
||||||
|
outboundFrom?: string
|
||||||
|
outboundTo?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WarehouseTransferSummaryDto {
|
export interface WarehouseTransferSummaryDto {
|
||||||
@@ -26,6 +32,12 @@ export interface WarehouseTransferSummaryDto {
|
|||||||
relabelNo?: string | null
|
relabelNo?: string | null
|
||||||
status: string
|
status: string
|
||||||
estimatedArrivalAt?: string | null
|
estimatedArrivalAt?: string | null
|
||||||
|
estimatedShipAt?: string | null
|
||||||
|
actualShipAt?: string | null
|
||||||
|
reviewedAt?: string | null
|
||||||
|
measuredAt?: string | null
|
||||||
|
outboundAt?: string | null
|
||||||
|
relabelCompletedAt?: string | null
|
||||||
createdAt?: string | null
|
createdAt?: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,6 +96,10 @@ export interface WarehouseTransferDetailDto extends WarehouseTransferSummaryDto
|
|||||||
relabelBindings: WarehouseTransferRelabelBindingDto[]
|
relabelBindings: WarehouseTransferRelabelBindingDto[]
|
||||||
customerConfirmedAt?: string | null
|
customerConfirmedAt?: string | null
|
||||||
actualShipAt?: string | null
|
actualShipAt?: string | null
|
||||||
|
reviewedAt?: string | null
|
||||||
|
measuredAt?: string | null
|
||||||
|
outboundAt?: string | null
|
||||||
|
relabelCompletedAt?: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function listWarehouseTransfers(customerId: string, query: WarehouseTransferQuery) {
|
export async function listWarehouseTransfers(customerId: string, query: WarehouseTransferQuery) {
|
||||||
|
|||||||
@@ -257,6 +257,21 @@ describe('LastMileOrdersView pending order and container conversion', () => {
|
|||||||
expect((button(wrapper, '生成入库计划')!.element as HTMLButtonElement).disabled).toBe(true)
|
expect((button(wrapper, '生成入库计划')!.element as HTMLButtonElement).disabled).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it.each(['WAREHOUSE_TRANSFER', 'RELABEL_APPLICATION', 'RETURN_RELABEL'])(
|
||||||
|
'does not offer an inbound plan for %s orders',
|
||||||
|
async (orderType) => {
|
||||||
|
canAccess.mockReturnValue(true)
|
||||||
|
vi.mocked(listLastMileOrders).mockResolvedValue({ records: [{
|
||||||
|
id: `order-${orderType}`, customerId, orderNo: `LM-${orderType}`, currentStatus: 'PENDING_REVIEW', orderType,
|
||||||
|
}], page: 1, size: 10, total: 1, pages: 1 })
|
||||||
|
|
||||||
|
const wrapper = await mountView()
|
||||||
|
const row = (wrapper.findComponent(DataTable).props('data') as object[])[0]
|
||||||
|
expect(wrapper.get('.el-table__body-wrapper .row-actions').text()).not.toContain('生成入库计划')
|
||||||
|
expect((wrapper.vm as unknown as { canGenerateInboundPlan: (source: object) => boolean }).canGenerateInboundPlan(row)).toBe(false)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
it('keeps the original pending order table and does not render a view switch or container table', async () => {
|
it('keeps the original pending order table and does not render a view switch or container table', async () => {
|
||||||
const wrapper = await openPending()
|
const wrapper = await openPending()
|
||||||
expect(wrapper.text()).toContain('尾程单号')
|
expect(wrapper.text()).toContain('尾程单号')
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import LoadErrorState from '@/shared/components/LoadErrorState.vue'
|
|||||||
import OperationErrorToast from '@/shared/components/OperationErrorToast.vue'
|
import OperationErrorToast from '@/shared/components/OperationErrorToast.vue'
|
||||||
import QueryToolbar, { type QueryField, type QueryModel } from '@/shared/components/QueryToolbar.vue'
|
import QueryToolbar, { type QueryField, type QueryModel } from '@/shared/components/QueryToolbar.vue'
|
||||||
import RowActions, { type RowActionItem } from '@/shared/components/RowActions.vue'
|
import RowActions, { type RowActionItem } from '@/shared/components/RowActions.vue'
|
||||||
import { changeContainerReceivingWarehouse, convertLastMileContainerToInboundPlans, createManualInboundPlan, downloadLastMileOrders, getContainerInboundPlanPreview, getContainerPlanProgress, getLastMileOrderManualNodes, listContainerPlanProgress, listLastMileOrders, reviewDirectRelabelOrder, reviewReturnOrder, 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, reviewCargoDiscardOrder, reviewDirectRelabelOrder, 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 OrderReferenceText from '../components/OrderReferenceText.vue'
|
||||||
import WarehouseTransferReviewDialog from '../components/WarehouseTransferReviewDialog.vue'
|
import WarehouseTransferReviewDialog from '../components/WarehouseTransferReviewDialog.vue'
|
||||||
import { confirmRelabelCompletion, getRelabelReviewTask, returnRelabelForRework } from '../api/relabelOrders'
|
import { confirmRelabelCompletion, getRelabelReviewTask, returnRelabelForRework } from '../api/relabelOrders'
|
||||||
@@ -446,6 +446,12 @@ function isRejectedReturn(source: object) {
|
|||||||
}
|
}
|
||||||
function hasSelectedRejectedReturn() { return selectedRows.value.some(isRejectedReturn) }
|
function hasSelectedRejectedReturn() { return selectedRows.value.some(isRejectedReturn) }
|
||||||
function hasSelectedInboundPlan() { return selectedRows.value.some(hasInboundPlan) }
|
function hasSelectedInboundPlan() { return selectedRows.value.some(hasInboundPlan) }
|
||||||
|
const inboundPlanExcludedOrderTypes = new Set(['WAREHOUSE_TRANSFER', 'RELABEL_APPLICATION', 'RETURN_RELABEL'])
|
||||||
|
function canGenerateInboundPlan(row: LastMileOrderListItem) {
|
||||||
|
// Older list responses expose the same value as orderType; keep the action
|
||||||
|
// gate correct while the API rollout is mixed across environments.
|
||||||
|
return !inboundPlanExcludedOrderTypes.has(String(row.orderTypeCode || row.orderType || ''))
|
||||||
|
}
|
||||||
async function loadTransferWarehouseOptions() {
|
async function loadTransferWarehouseOptions() {
|
||||||
transferWarehouseLoading.value = true
|
transferWarehouseLoading.value = true
|
||||||
transferWarehouseError.value = null
|
transferWarehouseError.value = null
|
||||||
@@ -500,6 +506,7 @@ function idempotencyKey(prefix: string) {
|
|||||||
function openInboundPlan(source?: object) {
|
function openInboundPlan(source?: object) {
|
||||||
const target = source ? source as LastMileOrderListItem : (selectedRows.value.length === 1 ? selectedRows.value[0] : null)
|
const target = source ? source as LastMileOrderListItem : (selectedRows.value.length === 1 ? selectedRows.value[0] : null)
|
||||||
if (!target) { ElMessage.warning('生成入库计划时请选择 1 条尾程订单'); return }
|
if (!target) { ElMessage.warning('生成入库计划时请选择 1 条尾程订单'); return }
|
||||||
|
if (!canGenerateInboundPlan(target)) { ElMessage.warning('当前业务单不需要生成入库计划'); return }
|
||||||
if (isRejectedReturn(target)) { ElMessage.warning('已驳回的退货预报只能查看详情'); return }
|
if (isRejectedReturn(target)) { ElMessage.warning('已驳回的退货预报只能查看详情'); return }
|
||||||
if (hasInboundPlan(target)) { ElMessage.warning('当前订单已提交入库计划,不能重复生成'); return }
|
if (hasInboundPlan(target)) { ElMessage.warning('当前订单已提交入库计划,不能重复生成'); return }
|
||||||
if (target.detained) { ElMessage.warning('订单处于暂扣状态,解除暂扣后才能生成入库计划'); return }
|
if (target.detained) { ElMessage.warning('订单处于暂扣状态,解除暂扣后才能生成入库计划'); return }
|
||||||
@@ -825,6 +832,26 @@ async function reviewDirectRelabel(source: object) {
|
|||||||
} else if (error !== 'close') ElMessage.error(getApiErrorDetails(error, '贴标单审核失败').message)
|
} else if (error !== 'close') ElMessage.error(getApiErrorDetails(error, '贴标单审核失败').message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
async function reviewCargoDiscard(source: object) {
|
||||||
|
const row = source as LastMileOrderListItem
|
||||||
|
const discardNo = row.orderNo
|
||||||
|
if (!discardNo || discardNo === '—' || !row.customerId) return
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm('审核通过后,货物废弃单将推送到 PDA,仓库按托盘填写实际废弃数量。', '货物废弃审核', { confirmButtonText: '审核通过', cancelButtonText: '驳回', distinguishCancelAndClose: true })
|
||||||
|
await reviewCargoDiscardOrder(discardNo, row.customerId, 'APPROVE')
|
||||||
|
ElMessage.success('货物废弃单已审核通过,已推送 PDA 废弃出库作业')
|
||||||
|
await load()
|
||||||
|
} catch (error) {
|
||||||
|
if (error === 'cancel') {
|
||||||
|
try {
|
||||||
|
const { value } = await ElMessageBox.prompt('请填写驳回原因', '驳回货物废弃单', { inputType: 'textarea', inputValidator: (input) => Boolean(input?.trim()) || '请填写驳回原因', confirmButtonText: '确认驳回', cancelButtonText: '取消' })
|
||||||
|
await reviewCargoDiscardOrder(discardNo, 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 canConfirmRelabel(row: { relabelStatusCode?: string }) { return row.relabelStatusCode === 'CUSTOMER_CONFIRM_PENDING' }
|
||||||
function canReworkRelabel(row: { relabelStatusCode?: string }) { return ['CUSTOMER_CONFIRM_PENDING', 'PROCESSING'].includes(row.relabelStatusCode ?? '') }
|
function canReworkRelabel(row: { relabelStatusCode?: string }) { return ['CUSTOMER_CONFIRM_PENDING', 'PROCESSING'].includes(row.relabelStatusCode ?? '') }
|
||||||
function hasRelabelActions(row: LastMileOrderListItem) {
|
function hasRelabelActions(row: LastMileOrderListItem) {
|
||||||
@@ -851,8 +878,9 @@ function lastMileRowActions(row: LastMileOrderListItem): RowActionItem[] {
|
|||||||
{ key: 'detail', label: '查看', priority: 500 },
|
{ key: 'detail', label: '查看', priority: 500 },
|
||||||
{ key: 'review-direct-relabel', label: '审核', priority: 470, tone: 'warning', visible: access.can(permission.lastMileOrderTransfer) && row.orderTypeCode === 'RELABEL_APPLICATION' && row.currentStatusCode === 'PENDING_REVIEW' },
|
{ key: 'review-direct-relabel', label: '审核', priority: 470, tone: 'warning', visible: access.can(permission.lastMileOrderTransfer) && row.orderTypeCode === 'RELABEL_APPLICATION' && row.currentStatusCode === 'PENDING_REVIEW' },
|
||||||
{ key: 'review-return', label: '审核', priority: 460, tone: 'warning', visible: access.can(permission.returnOrderReview) && row.orderTypeCode === 'RETURN_RELABEL' && row.currentStatusCode === 'PENDING_REVIEW' },
|
{ key: 'review-return', label: '审核', priority: 460, tone: 'warning', visible: access.can(permission.returnOrderReview) && row.orderTypeCode === 'RETURN_RELABEL' && row.currentStatusCode === 'PENDING_REVIEW' },
|
||||||
|
{ key: 'review-cargo-discard', label: '审核', priority: 455, tone: 'warning', visible: (access.can(permission.cargoDiscardApprove) || access.can(permission.warehouseTransferApprove)) && row.orderTypeCode === 'CARGO_DISCARD' && 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: '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) && !inboundPlanCreated },
|
{ key: 'inbound-plan', label: '生成入库计划', priority: 400, visible: access.can(permission.inboundOrderCreate) && canGenerateInboundPlan(row) && !inboundPlanCreated },
|
||||||
{ key: 'hold', label: row.detained ? '解除暂扣' : '暂扣订单', priority: 300, tone: 'warning', visible: access.can(permission.lastMileOrderTransfer) && (row.detained || row.currentStatusCode === 'INBOUND_COMPLETED') },
|
{ key: 'hold', label: row.detained ? '解除暂扣' : '暂扣订单', priority: 300, tone: 'warning', visible: access.can(permission.lastMileOrderTransfer) && (row.detained || row.currentStatusCode === 'INBOUND_COMPLETED') },
|
||||||
{ key: 'manual-nodes', label: '人工修改节点', priority: 200, visible: access.can(permission.lastMileOrderTransfer) },
|
{ key: 'manual-nodes', label: '人工修改节点', priority: 200, visible: access.can(permission.lastMileOrderTransfer) },
|
||||||
{ key: 'confirm-relabel', label: '换标完成确认', priority: 150, visible: access.can(permission.relabelOrderStatus) && Boolean(row.relabelOrderNo) && canConfirmRelabel(row) },
|
{ key: 'confirm-relabel', label: '换标完成确认', priority: 150, visible: access.can(permission.relabelOrderStatus) && Boolean(row.relabelOrderNo) && canConfirmRelabel(row) },
|
||||||
@@ -863,6 +891,7 @@ function handleLastMileRowAction(command: string, row: LastMileOrderListItem) {
|
|||||||
if (command === 'detail') openDetail(row)
|
if (command === 'detail') openDetail(row)
|
||||||
else if (command === 'review-direct-relabel') void reviewDirectRelabel(row)
|
else if (command === 'review-direct-relabel') void reviewDirectRelabel(row)
|
||||||
else if (command === 'review-return') void reviewReturn(row)
|
else if (command === 'review-return') void reviewReturn(row)
|
||||||
|
else if (command === 'review-cargo-discard') void reviewCargoDiscard(row)
|
||||||
else if (command === 'review') openTransferReview(row)
|
else if (command === 'review') openTransferReview(row)
|
||||||
else if (command === 'inbound-plan') openInboundPlan(row)
|
else if (command === 'inbound-plan') openInboundPlan(row)
|
||||||
else if (command === 'hold') openHold(row)
|
else if (command === 'hold') openHold(row)
|
||||||
@@ -962,7 +991,7 @@ onMounted(() => { void load() })
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</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()">
|
<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 || hasSelectedRejectedReturn() || actionLoading" @click="openTransfer">转仓</el-button><el-button v-if="access.can(permission.inboundOrderCreate)" type="primary" plain :disabled="selectedRows.length !== 1 || hasSelectedRejectedReturn() || hasSelectedInboundPlan() || 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) && selectedRows.length === 1 && canGenerateInboundPlan(selectedRows[0])" type="primary" plain :disabled="hasSelectedInboundPlan() || actionLoading" @click="openInboundPlan()">生成入库计划</el-button><el-button v-if="statusTab === '待分配' && access.can(permission.inboundOrderCreate)" type="primary" :disabled="actionLoading" @click="openContainerConversion">按柜批量生成</el-button></template>
|
||||||
<template #relabelOrderNo="{ row }"><div v-for="application in row.relabelApplications" :key="application.relabelNo" class="relabel-suborder">{{ application.relabelNo }}</div><span v-if="!row.relabelApplications?.length">{{ row.relabelOrderNo }}</span></template>
|
<template #relabelOrderNo="{ row }"><div v-for="application in row.relabelApplications" :key="application.relabelNo" class="relabel-suborder">{{ application.relabelNo }}</div><span v-if="!row.relabelApplications?.length">{{ row.relabelOrderNo }}</span></template>
|
||||||
<template #relabelStatus="{ row }"><div v-for="application in row.relabelApplications" :key="application.relabelNo" class="relabel-suborder">{{ application.statusLabel }} · {{ application.quantity }} 件</div><span v-if="!row.relabelApplications?.length">{{ row.relabelStatus }}</span></template>
|
<template #relabelStatus="{ row }"><div v-for="application in row.relabelApplications" :key="application.relabelNo" class="relabel-suborder">{{ application.statusLabel }} · {{ application.quantity }} 件</div><span v-if="!row.relabelApplications?.length">{{ row.relabelStatus }}</span></template>
|
||||||
<template #actions="{ row }"><RowActions :actions="lastMileRowActions(row as LastMileOrderListItem)" :more-label="`更多尾程订单操作 · ${(row as LastMileOrderListItem).orderNo || '当前记录'}`" @action="handleLastMileRowAction($event, row as LastMileOrderListItem)" /></template>
|
<template #actions="{ row }"><RowActions :actions="lastMileRowActions(row as LastMileOrderListItem)" :more-label="`更多尾程订单操作 · ${(row as LastMileOrderListItem).orderNo || '当前记录'}`" @action="handleLastMileRowAction($event, row as LastMileOrderListItem)" /></template>
|
||||||
|
|||||||
@@ -31,11 +31,14 @@ const warehousesLoading = ref(false)
|
|||||||
const page = ref(1)
|
const page = ref(1)
|
||||||
const pageSize = ref(10)
|
const pageSize = ref(10)
|
||||||
const total = ref(0)
|
const total = ref(0)
|
||||||
const filters = ref<QueryModel>({ relabelNo: '', sku: '', status: '' })
|
const filters = ref<QueryModel>({ relabelNo: '', sku: '', status: '', reviewedDates: [], measuredDates: [], outboundDates: [] })
|
||||||
const fields = computed<QueryField[]>(() => [
|
const fields = computed<QueryField[]>(() => [
|
||||||
{ key: 'relabelNo', type: 'input', label: '换标单号', placeholder: '请输入换标单号', width: 220 },
|
{ key: 'relabelNo', type: 'input', label: '换标单号', placeholder: '请输入换标单号', width: 220 },
|
||||||
{ key: 'sku', type: 'input', label: '商品SKU', placeholder: '请输入商品SKU', width: 180 },
|
{ key: 'sku', type: 'input', label: '商品SKU', placeholder: '请输入商品SKU', width: 180 },
|
||||||
{ key: 'status', type: 'select', label: '状态', placeholder: '全部状态', width: 160, options: [{ label: '待审核', value: 'PENDING_REVIEW' }, { 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' }] },
|
||||||
|
{ key: 'reviewedDates', type: 'daterange', label: '审核时间', width: 240 },
|
||||||
|
{ key: 'measuredDates', type: 'daterange', label: '测量时间', width: 240 },
|
||||||
|
{ key: 'outboundDates', type: 'daterange', label: '出库时间', width: 240 },
|
||||||
])
|
])
|
||||||
const columns: DataTableColumn[] = [
|
const columns: DataTableColumn[] = [
|
||||||
{ key: 'actions', label: '操作', width: 180, fixed: 'left', slotName: 'actions' },
|
{ key: 'actions', label: '操作', width: 180, fixed: 'left', slotName: 'actions' },
|
||||||
@@ -49,6 +52,9 @@ const columns: DataTableColumn[] = [
|
|||||||
{ key: 'labelRequirement', label: '贴标要求', minWidth: 150 },
|
{ key: 'labelRequirement', label: '贴标要求', minWidth: 150 },
|
||||||
{ key: 'fileName', label: '上传文件', minWidth: 160 },
|
{ key: 'fileName', label: '上传文件', minWidth: 160 },
|
||||||
{ key: 'status', label: '状态', width: 110 },
|
{ key: 'status', label: '状态', width: 110 },
|
||||||
|
{ key: 'reviewedAt', label: '审核时间', minWidth: 170 },
|
||||||
|
{ key: 'measuredAt', label: '测量时间', minWidth: 170 },
|
||||||
|
{ key: 'outboundAt', label: '出库时间', minWidth: 170 },
|
||||||
{ key: 'createdAt', label: '创建时间', minWidth: 170 },
|
{ key: 'createdAt', label: '创建时间', minWidth: 170 },
|
||||||
]
|
]
|
||||||
const dialogOpen = ref(false)
|
const dialogOpen = ref(false)
|
||||||
@@ -171,10 +177,13 @@ async function load(model: QueryModel = filters.value) {
|
|||||||
Object.assign(filters.value, model)
|
Object.assign(filters.value, model)
|
||||||
loading.value = true; loadError.value = null
|
loading.value = true; loadError.value = null
|
||||||
try {
|
try {
|
||||||
const result = await listRelabelOrders({ page: page.value, size: pageSize.value, relabelNo: String(filters.value.relabelNo || '').trim() || undefined, skuCode: String(filters.value.sku || '').trim() || undefined, status: String(filters.value.status || '').trim() || undefined })
|
const reviewedDates = Array.isArray(filters.value.reviewedDates) ? filters.value.reviewedDates : []
|
||||||
|
const measuredDates = Array.isArray(filters.value.measuredDates) ? filters.value.measuredDates : []
|
||||||
|
const outboundDates = Array.isArray(filters.value.outboundDates) ? filters.value.outboundDates : []
|
||||||
|
const result = await listRelabelOrders({ page: page.value, size: pageSize.value, relabelNo: String(filters.value.relabelNo || '').trim() || undefined, skuCode: String(filters.value.sku || '').trim() || undefined, status: String(filters.value.status || '').trim() || undefined, reviewedFrom: String(reviewedDates[0] || '') || undefined, reviewedTo: String(reviewedDates[1] || '') || undefined, measuredFrom: String(measuredDates[0] || '') || undefined, measuredTo: String(measuredDates[1] || '') || undefined, outboundFrom: String(outboundDates[0] || '') || undefined, outboundTo: String(outboundDates[1] || '') || undefined })
|
||||||
rows.value = result.records.map((item) => ({
|
rows.value = result.records.map((item) => ({
|
||||||
customerId: '', orderNo: String(item.relabelNo), relatedOrderNo: String(item.lastlegOrderNo || item.customerOrderNo || '—'), sku: String(item.skuCodes || '—'),
|
customerId: '', orderNo: String(item.relabelNo), relatedOrderNo: String(item.lastlegOrderNo || item.customerOrderNo || '—'), sku: String(item.skuCodes || '—'),
|
||||||
productName: '—', cartons: Number(item.totalPackageCount || 0), budgetTotal: null, relabelCost: Number(item.chargeAmount || 0), walletStatus: walletStatus(item.walletStatus), walletErrorMessage: item.walletErrorMessage || '', labelRequirement: '—', fileName: '—', status: relabelStatus(item.status), rawStatus: String(item.status || ''), remark: '',
|
productName: '—', cartons: Number(item.totalPackageCount || 0), budgetTotal: null, relabelCost: Number(item.chargeAmount || 0), walletStatus: walletStatus(item.walletStatus), walletErrorMessage: item.walletErrorMessage || '', labelRequirement: '—', fileName: '—', status: relabelStatus(item.status), rawStatus: String(item.status || ''), remark: '', reviewedAt: item.reviewedAt, measuredAt: item.measuredAt, outboundAt: item.outboundAt,
|
||||||
reviewChannel: item.reviewChannel || undefined,
|
reviewChannel: item.reviewChannel || undefined,
|
||||||
createdAt: formatOverseasDateTime(item.createdAt),
|
createdAt: formatOverseasDateTime(item.createdAt),
|
||||||
}))
|
}))
|
||||||
|
|||||||
@@ -409,7 +409,7 @@ describe('overseas warehouse first-batch prototype contract', () => {
|
|||||||
'inTransit', 'updatedAt',
|
'inTransit', 'updatedAt',
|
||||||
])
|
])
|
||||||
expect(columnKeys('RelabelOrdersView.vue')).toEqual([
|
expect(columnKeys('RelabelOrdersView.vue')).toEqual([
|
||||||
'actions', 'orderNo', 'sku', 'productName', 'cartons', 'budgetTotal', 'relabelCost', 'walletStatus', 'labelRequirement', 'fileName', 'status', 'createdAt',
|
'actions', 'orderNo', 'sku', 'productName', 'cartons', 'budgetTotal', 'relabelCost', 'walletStatus', 'labelRequirement', 'fileName', 'status', 'reviewedAt', 'measuredAt', 'outboundAt', 'createdAt',
|
||||||
])
|
])
|
||||||
expect(columnKeys('PalletsView.vue')).toEqual([
|
expect(columnKeys('PalletsView.vue')).toEqual([
|
||||||
'actions', 'code', 'type', 'warehouse', 'volume', 'purchasePrice', 'fbaWarehouse', 'status', 'remark',
|
'actions', 'code', 'type', 'warehouse', 'volume', 'purchasePrice', 'fbaWarehouse', 'status', 'remark',
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ export const overseasWarehousePermissions = {
|
|||||||
lastMileOrderExport: 'platform:overseas-warehouse:last-mile-order:export',
|
lastMileOrderExport: 'platform:overseas-warehouse:last-mile-order:export',
|
||||||
lastMileOrderTransfer: 'platform:overseas-warehouse:last-mile-order:edit',
|
lastMileOrderTransfer: 'platform:overseas-warehouse:last-mile-order:edit',
|
||||||
warehouseTransferApprove: 'platform:overseas-warehouse:warehouse-transfer:approve',
|
warehouseTransferApprove: 'platform:overseas-warehouse:warehouse-transfer:approve',
|
||||||
|
cargoDiscardApprove: 'platform:overseas-warehouse:discard:approve',
|
||||||
inboundOrderList: 'platform:overseas-warehouse:inbound-order:list',
|
inboundOrderList: 'platform:overseas-warehouse:inbound-order:list',
|
||||||
inboundOrderCreate: 'platform:overseas-warehouse:inbound-order:create',
|
inboundOrderCreate: 'platform:overseas-warehouse:inbound-order:create',
|
||||||
inboundOrderEdit: 'platform:overseas-warehouse:inbound-order:edit',
|
inboundOrderEdit: 'platform:overseas-warehouse:inbound-order:edit',
|
||||||
|
|||||||
@@ -153,6 +153,9 @@ export interface RelabelOrderListItem {
|
|||||||
status: string
|
status: string
|
||||||
rawStatus?: string
|
rawStatus?: string
|
||||||
reviewChannel?: 'TAIL_ORDER' | 'RELABEL_ORDER'
|
reviewChannel?: 'TAIL_ORDER' | 'RELABEL_ORDER'
|
||||||
|
reviewedAt?: string | null
|
||||||
|
measuredAt?: string | null
|
||||||
|
outboundAt?: string | null
|
||||||
remark: string
|
remark: string
|
||||||
createdAt: string
|
createdAt: string
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user