优化
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
import '@/styles/adminDensity.css'
|
||||
import { computed, onMounted, reactive, ref, watch } from 'vue'
|
||||
import { Download, Pencil, MoreHorizontal } from '@lucide/vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { listAllPlatformWarehouses, type PlatformWarehouseSummaryResource } from '@/modules/warehouses'
|
||||
import { getApiErrorDetails, type ApiErrorDetails } from '@/shared/api/http'
|
||||
@@ -17,9 +17,10 @@ import QueryToolbar, { type QueryField, type QueryModel } from '@/shared/compone
|
||||
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 OrderReferenceText from '../components/OrderReferenceText.vue'
|
||||
import WarehouseTransferReviewDialog from '../components/WarehouseTransferReviewDialog.vue'
|
||||
import { confirmRelabelCompletion, getRelabelReviewTask, returnRelabelForRework } from '../api/relabelOrders'
|
||||
import { useAccessPreviewStore } from '@/core/access/accessPreview'
|
||||
import { overseasWarehousePermissions as permission } from '../permissions'
|
||||
import { lastMileStatusLabel, toLastMileOrderListItem } from '../lastMilePresentation'
|
||||
import { lastMileStatusLabel, packageDifferenceText, toLastMileOrderListItem } from '../lastMilePresentation'
|
||||
import type { LastMileOrderListItem } from '../types'
|
||||
import { saveCsv } from '@/shared/downloadCsv'
|
||||
|
||||
@@ -133,6 +134,9 @@ const allFields: QueryField[] = [
|
||||
{ key: 'transferWarehouseCode', type: 'input', label: '转仓代码', width: 170, placeholder: '请输入转仓代码' },
|
||||
{ key: 'status', type: 'select', label: '当前状态', width: 160, placeholder: '全部状态', options: [
|
||||
{ label: '待分配', value: 'PENDING_ASSIGNMENT' },
|
||||
{ label: '待换标', value: 'WAIT_RELABEL' },
|
||||
{ label: '待排车', value: 'READY_FOR_DISPATCH' },
|
||||
{ label: '待出库', value: 'WAIT_OUTBOUND' },
|
||||
{ label: '待入库', value: 'PENDING_INBOUND' },
|
||||
{ label: '入库完成', value: 'INBOUND_COMPLETED' },
|
||||
{ label: '待派送', value: 'PENDING_DELIVERY' },
|
||||
@@ -218,6 +222,7 @@ const columns: DataTableColumn[] = [
|
||||
{ key: 'held', prop: 'held', label: '是否暂扣', width: 100 },
|
||||
{ key: 'pallets', prop: 'pallets', label: '托数', width: 80, align: 'right' },
|
||||
{ key: 'cartons', prop: 'cartons', label: '箱数', width: 80, align: 'right' },
|
||||
{ key: 'cartonDifference', prop: 'cartonDifference', label: '差异(箱)', width: 100, align: 'right', slotName: 'cartonDifference' },
|
||||
{ key: 'volume', prop: 'volume', label: '体积(m³)', width: 100, align: 'right' },
|
||||
{ key: 'quantity', prop: 'quantity', label: '数量', width: 80, align: 'right' },
|
||||
{ key: 'volumeWeight', prop: 'volumeWeight', label: '体积重量', width: 100, align: 'right' },
|
||||
@@ -770,10 +775,40 @@ watch(containerConvertOpen, (open) => {
|
||||
|
||||
function rowActionCount(source: object) {
|
||||
const row = source as LastMileOrderListItem
|
||||
return 1
|
||||
const count = 1
|
||||
+ Number(access.can(permission.warehouseTransferApprove) && row.orderTypeCode === 'WAREHOUSE_TRANSFER' && 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
|
||||
}
|
||||
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 hasRelabelActions(source: object) {
|
||||
const row = source as LastMileOrderListItem
|
||||
return access.can(permission.relabelOrderStatus) && Boolean(row.relabelOrderNo) && (canConfirmRelabel(row) || canReworkRelabel(row))
|
||||
}
|
||||
async function confirmRelabel(row: { relabelOrderNo?: string }) {
|
||||
const relabelNo = row.relabelOrderNo
|
||||
if (!relabelNo) return
|
||||
try {
|
||||
await ElMessageBox.confirm('确认仓库上传的换标结果无误并继续后续流程吗?', '换标完成确认', { confirmButtonText: '确认并继续', cancelButtonText: '取消' })
|
||||
await confirmRelabelCompletion(relabelNo)
|
||||
ElMessage.success('已确认换标完成')
|
||||
await load()
|
||||
} catch (error) { if (error !== 'cancel' && error !== 'close') ElMessage.error(getApiErrorDetails(error, '换标完成确认失败').message) }
|
||||
}
|
||||
async function reworkRelabel(row: { relabelOrderNo?: string }) {
|
||||
const relabelNo = row.relabelOrderNo
|
||||
if (!relabelNo) return
|
||||
try {
|
||||
const task = await getRelabelReviewTask(relabelNo)
|
||||
const { value } = await ElMessageBox.prompt('填写退回原因,仓库将重新执行换标并上传照片。', '重新换标', { inputType: 'textarea', inputValidator: (value) => Boolean(value?.trim()) && value.trim().length <= 1000 || '请填写 1 至 1000 字原因', confirmButtonText: '确认重新换标', cancelButtonText: '取消' })
|
||||
await returnRelabelForRework(relabelNo, task.version, value.trim(), crypto.randomUUID())
|
||||
ElMessage.success('已退回重新换标')
|
||||
await load()
|
||||
} catch (error) { if (error !== 'cancel' && error !== 'close') ElMessage.error(getApiErrorDetails(error, '重新换标失败').message) }
|
||||
}
|
||||
function openDetail(source: object) {
|
||||
const row = source as LastMileOrderListItem
|
||||
@@ -847,8 +882,9 @@ onMounted(() => { void load() })
|
||||
</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 #actions="{ row }"><div class="row-actions density-actions"><el-button class="density-action" data-tone="neutral" size="small" @click="openDetail(row)">查看</el-button><el-button class="density-action" data-tone="warning" v-if="access.can(permission.warehouseTransferApprove) && row.orderTypeCode === 'WAREHOUSE_TRANSFER' && row.currentStatusCode === 'PENDING_REVIEW'" size="small" @click="openTransferReview(row)">审核</el-button><el-button class="density-action" data-tone="neutral" v-if="access.can(permission.inboundOrderCreate)" :disabled="row.detained" size="small" @click="openInboundPlan(row)">入库计划</el-button><template v-if="rowActionCount(row) <= 3 && access.can(permission.lastMileOrderTransfer)"><el-button class="density-action" data-tone="warning" size="small" @click="openHold(row)">{{ row.detained ? '解除暂扣' : '暂扣订单' }}</el-button><el-button class="density-action" data-tone="neutral" size="small" @click="openManualNodes(row)">人工修改节点</el-button></template><el-dropdown v-if="rowActionCount(row) > 3" trigger="click"><el-button class="density-action" :aria-label="`更多操作 · ${row.orderNo || row.dispatchNo || '当前记录'}`" title="更多操作" data-tone="neutral" size="small" ><MoreHorizontal aria-hidden="true" :size="15" /></el-button><template #dropdown><el-dropdown-menu><el-dropdown-item v-if="access.can(permission.lastMileOrderTransfer)" @click="openHold(row)">{{ row.detained ? '解除暂扣' : '暂扣订单' }}</el-dropdown-item><el-dropdown-item v-if="access.can(permission.lastMileOrderTransfer)" @click="openManualNodes(row)">人工修改节点</el-dropdown-item></el-dropdown-menu></template></el-dropdown></div></template>
|
||||
<template #actions="{ row }"><div class="row-actions density-actions"><el-button class="density-action" data-tone="neutral" size="small" @click="openDetail(row)">查看</el-button><el-button class="density-action" data-tone="warning" v-if="access.can(permission.warehouseTransferApprove) && row.orderTypeCode === 'WAREHOUSE_TRANSFER' && row.currentStatusCode === 'PENDING_REVIEW'" size="small" @click="openTransferReview(row)">审核</el-button><el-button class="density-action" data-tone="neutral" v-if="access.can(permission.inboundOrderCreate)" :disabled="row.detained" size="small" @click="openInboundPlan(row)">入库计划</el-button><template v-if="rowActionCount(row) <= 3 && access.can(permission.lastMileOrderTransfer)"><el-button class="density-action" data-tone="warning" size="small" @click="openHold(row)">{{ row.detained ? '解除暂扣' : '暂扣订单' }}</el-button><el-button class="density-action" data-tone="neutral" size="small" @click="openManualNodes(row)">人工修改节点</el-button></template><el-dropdown v-if="rowActionCount(row) > 3" trigger="click"><el-button class="density-action" :aria-label="`更多操作 · ${row.orderNo || row.dispatchNo || '当前记录'}`" title="更多操作" data-tone="neutral" size="small" ><MoreHorizontal aria-hidden="true" :size="15" /></el-button><template #dropdown><el-dropdown-menu><el-dropdown-item v-if="access.can(permission.lastMileOrderTransfer)" @click="openHold(row)">{{ row.detained ? '解除暂扣' : '暂扣订单' }}</el-dropdown-item><el-dropdown-item v-if="access.can(permission.lastMileOrderTransfer)" @click="openManualNodes(row)">人工修改节点</el-dropdown-item><el-dropdown-item v-if="access.can(permission.relabelOrderStatus) && row.relabelOrderNo && canConfirmRelabel(row)" @click="confirmRelabel(row)">换标完成确认</el-dropdown-item><el-dropdown-item v-if="access.can(permission.relabelOrderStatus) && row.relabelOrderNo && canReworkRelabel(row)" @click="reworkRelabel(row)">重新换标</el-dropdown-item></el-dropdown-menu></template></el-dropdown></div></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>
|
||||
<template #pagination-left>共 {{ total }} 条尾程订单 · 已选 {{ selectedRows.length }} 条</template>
|
||||
</DataTable></section>
|
||||
</ListPageLayout></AdminPage>
|
||||
@@ -1054,5 +1090,6 @@ onMounted(() => { void load() })
|
||||
.container-preview__metric { display: flex; min-height: var(--admin-row-height); padding: var(--admin-space-5) var(--admin-space-5); border: 0; border-radius: 0; background: var(--admin-surface); flex-direction: row; justify-content: flex-start; align-items: baseline; gap: var(--admin-space-3); border-right: 1px solid var(--cc-border); }
|
||||
.container-preview__metric:last-child { border-right: 0; }
|
||||
.container-preview__metric strong { margin-top: var(--admin-space-1); color: var(--cc-text); font-size: var(--admin-font-body); line-height: 20px; margin: 0; }
|
||||
.package-difference--nonzero { color: var(--el-color-danger); font-weight: 600; }
|
||||
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user