优化
This commit is contained in:
@@ -10,6 +10,7 @@ import {
|
||||
batchApprovePlatformUnifiedOrders,
|
||||
addPlatformUnifiedOrderNote,
|
||||
listPlatformUnifiedOrders,
|
||||
updatePlatformUnifiedOrderPlanning,
|
||||
unifiedOrderStatusOptions,
|
||||
type UnifiedOrderDetailResource,
|
||||
type UnifiedOrderCoLoadGroupSummary,
|
||||
@@ -110,6 +111,15 @@ const pageSize = ref(20)
|
||||
const total = ref(0)
|
||||
const loading = ref(false)
|
||||
const loadError = ref<ApiErrorDetails | null>(null)
|
||||
type PlanningDraft = {
|
||||
expectedArrivalAt: string
|
||||
estimatedVolumeCbm: number | null
|
||||
savedExpectedArrivalAt: string
|
||||
savedEstimatedVolumeCbm: number | null
|
||||
saving: boolean
|
||||
error: ApiErrorDetails | null
|
||||
}
|
||||
const planningDrafts = reactive<Record<string, PlanningDraft | undefined>>({})
|
||||
const customerLoading = ref(false)
|
||||
const customerLoadError = ref<ApiErrorDetails | null>(null)
|
||||
const warehouseLoading = ref(false)
|
||||
@@ -455,18 +465,19 @@ const columns = computed<DataTableColumn[]>(() => [
|
||||
{ key: 'destinationWarehouseName', prop: 'destinationWarehouseName', label: '目的仓', minWidth: 150, slotName: 'field' },
|
||||
{ key: 'channelName', prop: 'channelName', label: '渠道', minWidth: 180, slotName: 'channel' },
|
||||
{ key: 'totalPackageCount', prop: 'totalPackageCount', label: '总箱数', minWidth: 100, slotName: 'field' },
|
||||
{ key: 'expectedVolumeCbm', prop: 'expectedVolumeCbm', label: '预计体积(m³)', minWidth: 130, slotName: 'field' },
|
||||
{ key: 'expectedArrivalAt', prop: 'expectedArrivalAt', label: '预计到货时间', minWidth: 220, slotName: 'expectedArrival' },
|
||||
{ key: 'estimatedVolumeCbm', prop: 'estimatedVolumeCbm', label: '预估体积(m³)', minWidth: 180, slotName: 'estimatedVolume' },
|
||||
{ key: 'expectedVolumeCbm', prop: 'expectedVolumeCbm', label: '下单体积(m³)', minWidth: 130, slotName: 'field' },
|
||||
{ key: 'actualVolumeCbm', prop: 'actualVolumeCbm', label: '实测体积(m³)', minWidth: 130, slotName: 'field' },
|
||||
{ key: 'totalPalletCount', prop: 'totalPalletCount', label: '总托数', minWidth: 100, slotName: 'field' },
|
||||
{ key: 'requestedPickupAt', prop: 'requestedPickupAt', label: '预约提货时间', minWidth: 160, slotName: 'field' },
|
||||
{ key: 'locationCodes', prop: 'locationCodes', label: '库位位置', minWidth: 160, slotName: 'field', defaultVisible: false },
|
||||
{ key: 'measurementReviewStatus', prop: 'measurementReviewStatus', label: '测量数据审核状态', minWidth: 170, slotName: 'measurementReviewStatus' },
|
||||
{ key: 'actualGrossWeightKg', prop: 'actualGrossWeightKg', label: '实测毛重(kg)', minWidth: 130, slotName: 'field' },
|
||||
{ key: 'actualVolumeCbm', prop: 'actualVolumeCbm', label: '实测体积(m³)', minWidth: 130, slotName: 'field' },
|
||||
{ key: 'totalNetWeightKg', prop: 'totalNetWeightKg', label: '货物净重(kg)', minWidth: 130, slotName: 'field' },
|
||||
{ key: 'chargeableWeightKg', prop: 'chargeableWeightKg', label: '计费毛重', minWidth: 120, slotName: 'field' },
|
||||
{ key: 'chargeableVolumeCbm', prop: 'chargeableVolumeCbm', label: '计费体积(m³)', minWidth: 130, slotName: 'field' },
|
||||
{ key: 'expectedShipDate', prop: 'expectedShipDate', label: '预计出运日期', minWidth: 150, slotName: 'field' },
|
||||
{ key: 'expectedArrivalAt', prop: 'expectedArrivalAt', label: '预计到货时间', minWidth: 160, slotName: 'field' },
|
||||
{ key: 'feeReviewStatus', prop: 'feeReviewStatus', label: '费用审核状态', minWidth: 140, slotName: 'field', defaultVisible: false },
|
||||
{ key: 'skuNos', prop: 'skuNos', label: 'SKU 编码', minWidth: 180, slotName: 'field', defaultVisible: false },
|
||||
{ key: 'totalQuantity', prop: 'totalQuantity', label: '货物总数量', minWidth: 120, slotName: 'field', defaultVisible: false },
|
||||
@@ -533,6 +544,60 @@ function can(permission: string) {
|
||||
return access.can(permission)
|
||||
}
|
||||
|
||||
function planningDraft(row: UnifiedOrderResource) {
|
||||
const key = String(row.orderId)
|
||||
let draft = planningDrafts[key]
|
||||
if (!draft) {
|
||||
draft = {
|
||||
expectedArrivalAt: row.expectedArrivalAt || '',
|
||||
estimatedVolumeCbm: row.estimatedVolumeCbm ?? null,
|
||||
savedExpectedArrivalAt: row.expectedArrivalAt || '',
|
||||
savedEstimatedVolumeCbm: row.estimatedVolumeCbm ?? null,
|
||||
saving: false,
|
||||
error: null,
|
||||
}
|
||||
planningDrafts[key] = draft
|
||||
}
|
||||
return draft
|
||||
}
|
||||
|
||||
async function savePlanning(row: UnifiedOrderResource) {
|
||||
const draft = planningDraft(row)
|
||||
if (!can('platform:order:declaration:edit') || draft.saving) return
|
||||
const estimatedVolumeCbm = draft.estimatedVolumeCbm ?? null
|
||||
draft.estimatedVolumeCbm = estimatedVolumeCbm
|
||||
if (!Number.isInteger(row.orderVersion)) {
|
||||
draft.error = { message: '订单版本缺失,请刷新列表后重试' }
|
||||
return
|
||||
}
|
||||
if (estimatedVolumeCbm !== null && (!Number.isFinite(estimatedVolumeCbm) || estimatedVolumeCbm <= 0)) {
|
||||
draft.error = { message: '预估体积必须大于 0,或清空该值' }
|
||||
return
|
||||
}
|
||||
if (draft.expectedArrivalAt === draft.savedExpectedArrivalAt
|
||||
&& estimatedVolumeCbm === draft.savedEstimatedVolumeCbm) return
|
||||
|
||||
draft.saving = true
|
||||
draft.error = null
|
||||
try {
|
||||
const result = await updatePlatformUnifiedOrderPlanning(String(row.tenantId), String(row.orderId), {
|
||||
expectedVersion: row.orderVersion!,
|
||||
expectedArrivalAt: draft.expectedArrivalAt || null,
|
||||
estimatedVolumeCbm,
|
||||
})
|
||||
row.orderVersion = result.version
|
||||
row.expectedArrivalAt = draft.expectedArrivalAt || null
|
||||
row.estimatedVolumeCbm = estimatedVolumeCbm
|
||||
draft.savedExpectedArrivalAt = draft.expectedArrivalAt
|
||||
draft.savedEstimatedVolumeCbm = estimatedVolumeCbm
|
||||
ElMessage.success('订单运营预估已更新')
|
||||
} catch (error) {
|
||||
draft.error = getApiErrorDetails(error, '订单运营预估保存失败')
|
||||
} finally {
|
||||
draft.saving = false
|
||||
}
|
||||
}
|
||||
|
||||
const canEditDeclaration = computed(() => Boolean(
|
||||
detail.value
|
||||
&& detail.value.summary.mainStatus === 'WAIT_MEASURE'
|
||||
@@ -766,7 +831,7 @@ async function updateMeasurementCalculationMode(row: Record<string, unknown> | n
|
||||
version: measurement.version,
|
||||
actualGoodsName: measurement.actualGoodsName,
|
||||
items: measurement.items.map((item) => ({
|
||||
inboundDetailId: item.inboundDetailId,
|
||||
inboundDetailId: item.inboundDetailId || undefined,
|
||||
boxCode: item.boxCode,
|
||||
itemNo: item.itemNo,
|
||||
boxSpecification: item.boxSpecification,
|
||||
@@ -827,7 +892,7 @@ async function saveWarehouseOuterDimensions(row: Record<string, unknown>) {
|
||||
version: measurement.version,
|
||||
actualGoodsName: measurement.actualGoodsName,
|
||||
items: measurement.items.map((item) => ({
|
||||
inboundDetailId: item.inboundDetailId,
|
||||
inboundDetailId: item.inboundDetailId || undefined,
|
||||
boxCode: item.boxCode,
|
||||
itemNo: item.itemNo,
|
||||
boxSpecification: item.boxSpecification,
|
||||
@@ -1142,6 +1207,7 @@ async function loadOrders() {
|
||||
loading.value = true
|
||||
loadError.value = null
|
||||
coLoadError.value = null
|
||||
Object.keys(planningDrafts).forEach((key) => delete planningDrafts[key])
|
||||
try {
|
||||
const activeFilters = appliedFilters.value
|
||||
const range = activeFilters.createdRange
|
||||
@@ -2075,6 +2141,51 @@ onBeforeUnmount(() => {
|
||||
<template #orderStatus="{ row }"><StatusBadge :status="orderStatusLabel((row as UnifiedOrderResource).internalOrderStatus || (row as UnifiedOrderResource).mainStatus)" /></template>
|
||||
<template #measurementReviewStatus="{ row }"><StatusBadge :status="measurementStatusLabel((row as UnifiedOrderResource).measurement?.reviewStatus)" /></template>
|
||||
<template #channel="{ row }"><div class="channel-cell"><span>{{ (row as UnifiedOrderResource).channelName || '—' }}</span><el-tag v-if="(row as UnifiedOrderResource).channelChanged" size="small" type="warning">曾变更渠道</el-tag></div></template>
|
||||
<template #estimatedVolume="{ row }">
|
||||
<div class="planning-cell">
|
||||
<el-input-number
|
||||
v-if="can('platform:order:declaration:edit')"
|
||||
v-model="planningDraft(row as UnifiedOrderResource).estimatedVolumeCbm"
|
||||
class="planning-volume-input"
|
||||
:min="0.0001"
|
||||
:precision="4"
|
||||
:controls="false"
|
||||
:disabled="planningDraft(row as UnifiedOrderResource).saving"
|
||||
placeholder="填写预估体积"
|
||||
:aria-label="`修改 ${(row as UnifiedOrderResource).inboundCode || '当前订单'} 预估体积`"
|
||||
@change="savePlanning(row as UnifiedOrderResource)"
|
||||
/>
|
||||
<span v-else>{{ formatNumber((row as UnifiedOrderResource).estimatedVolumeCbm, 4) }}</span>
|
||||
<small v-if="planningDraft(row as UnifiedOrderResource).saving">保存中…</small>
|
||||
<div v-if="planningDraft(row as UnifiedOrderResource).error" class="planning-error" role="alert">
|
||||
<span>{{ planningDraft(row as UnifiedOrderResource).error?.message }}</span>
|
||||
<ApiErrorMeta :details="planningDraft(row as UnifiedOrderResource).error!" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #expectedArrival="{ row }">
|
||||
<div class="planning-cell">
|
||||
<el-date-picker
|
||||
v-if="can('platform:order:declaration:edit')"
|
||||
v-model="planningDraft(row as UnifiedOrderResource).expectedArrivalAt"
|
||||
class="planning-arrival-input"
|
||||
type="datetime"
|
||||
value-format="YYYY-MM-DDTHH:mm:ss"
|
||||
format="YYYY-MM-DD HH:mm"
|
||||
clearable
|
||||
:disabled="planningDraft(row as UnifiedOrderResource).saving"
|
||||
placeholder="选择预计到货时间"
|
||||
:aria-label="`修改 ${(row as UnifiedOrderResource).inboundCode || '当前订单'} 预计到货时间`"
|
||||
@change="savePlanning(row as UnifiedOrderResource)"
|
||||
/>
|
||||
<span v-else>{{ formatDate((row as UnifiedOrderResource).expectedArrivalAt) }}</span>
|
||||
<small v-if="planningDraft(row as UnifiedOrderResource).saving">保存中…</small>
|
||||
<div v-if="planningDraft(row as UnifiedOrderResource).error" class="planning-error" role="alert">
|
||||
<span>{{ planningDraft(row as UnifiedOrderResource).error?.message }}</span>
|
||||
<ApiErrorMeta :details="planningDraft(row as UnifiedOrderResource).error!" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #field="{ row, column }"><LineClampText v-if="['customerRemark', 'latestInternalNote'].includes(String(column.property))" :content="displayField(row as UnifiedOrderResource, column.property)" :lines="2" /><template v-else>{{ displayField(row as UnifiedOrderResource, column.property) }}</template></template>
|
||||
<template #mainStatus="{ row }"><StatusBadge :status="statusLabel((row as UnifiedOrderResource).mainStatus)" /></template>
|
||||
<template #customer="{ row }"><div class="primary-cell"><strong>{{ customerName(row as UnifiedOrderResource) }}</strong></div></template>
|
||||
@@ -2218,6 +2329,13 @@ onBeforeUnmount(() => {
|
||||
.table-card :deep(.el-table__body tr:hover > td.el-table__cell) { background: #f3f7fb; }
|
||||
.row-actions { display: flex; align-items: center; gap: 4px; white-space: nowrap; }
|
||||
.row-actions :deep(.el-button) { margin-left: 0; }
|
||||
.planning-cell { display: grid; min-width: 0; gap: 4px; }
|
||||
.planning-cell > small { color: var(--cc-muted); font-size: 11px; }
|
||||
.planning-volume-input,.planning-arrival-input { width: 100%; max-width: 100%; }
|
||||
.planning-cell :deep(.el-input__wrapper) { min-height: 32px; padding-right: 9px; padding-left: 9px; }
|
||||
.planning-cell :deep(.el-input__inner) { min-width: 0; text-align: left; }
|
||||
.planning-error { min-width: 0; color: var(--el-color-danger); font-size: 11px; line-height: 1.35; white-space: normal; }
|
||||
.planning-error :deep(.api-error-meta) { margin-top: 3px; }
|
||||
.inbound-relation-cell { display: grid; min-width: 0; gap: 5px; }
|
||||
.inbound-code-value { display: block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.order-relation-link { width: fit-content; max-width: 100%; height: auto; justify-content: flex-start; padding: 0; font-size: 12px; }
|
||||
|
||||
Reference in New Issue
Block a user