优化
This commit is contained in:
@@ -4,6 +4,18 @@ export interface PageResult<T> { records: T[]; page: number; size: number; total
|
|||||||
export interface LastlegOrderSummary { id: string; orderNo: string; inboundCode: string; orderType: string; packageCount: number; overseasWarehouseId?: string }
|
export interface LastlegOrderSummary { id: string; orderNo: string; inboundCode: string; orderType: string; packageCount: number; overseasWarehouseId?: string }
|
||||||
export interface TransferSummary { id: string; transferNo: string; inboundCode: string; lastlegOrderId: string; lastlegOrderNo: string; operatingWarehouseId: string; fbaWarehouseCode: string; packageCount: number; deliveryMethod: string; needRelabel: boolean; relabelNo?: string; status: string; estimatedArrivalAt: string; createdAt: string }
|
export interface TransferSummary { id: string; transferNo: string; inboundCode: string; lastlegOrderId: string; lastlegOrderNo: string; operatingWarehouseId: string; fbaWarehouseCode: string; packageCount: number; deliveryMethod: string; needRelabel: boolean; relabelNo?: string; status: string; estimatedArrivalAt: string; createdAt: string }
|
||||||
export interface RelabelSummary { id: string; relabelNo: string; lastlegOrderId: string; lastlegOrderNo: string; customerOrderNo: string; overseasWarehouseId: string; status: string; itemCount: number; totalPackageCount: number; notifiedPackageCount: number; skuCodes: string; createdAt: string }
|
export interface RelabelSummary { id: string; relabelNo: string; lastlegOrderId: string; lastlegOrderNo: string; customerOrderNo: string; overseasWarehouseId: string; status: string; itemCount: number; totalPackageCount: number; notifiedPackageCount: number; skuCodes: string; createdAt: string }
|
||||||
|
export interface RelabelItemDetail {
|
||||||
|
id: string; skuCode?: string; productNameZh: string; totalPackageCount: number; notifiedPackageCount: number
|
||||||
|
shipmentNo: string; trackingCode?: string; newSkuCode: string; labelRequirement?: string; remark?: string
|
||||||
|
relabelFileId?: string; relabelFileName?: string; relabelFileUrl?: string
|
||||||
|
cartonMark: string; fbaCartonMark: string; destinationWarehouseId: string
|
||||||
|
}
|
||||||
|
export interface RelabelDetail {
|
||||||
|
application: RelabelSummary & { labelDeadline?: string; contactName?: string; contactPhone?: string; chargeAmount?: number; chargeCurrency?: string; walletStatus?: string; walletErrorMessage?: string }
|
||||||
|
remark?: string; items: RelabelItemDetail[]
|
||||||
|
history: Array<{ fromStatus?: string; toStatus?: string; operatorId?: string; remark?: string; createdAt: string }>
|
||||||
|
tailOrders?: Array<{ id: string; orderNo: string; overseasWarehouseId: string; packageCount: number; status: string }>
|
||||||
|
}
|
||||||
export interface DiscardSummary { id: string; discardNo: string; inboundCodes: string; overseasWarehouseId: string; overseasWarehouseName: string; totalPackages: number; totalFee: number; currency: string; status: string; createdAt: string }
|
export interface DiscardSummary { id: string; discardNo: string; inboundCodes: string; overseasWarehouseId: string; overseasWarehouseName: string; totalPackages: number; totalFee: number; currency: string; status: string; createdAt: string }
|
||||||
export interface DiscardCandidate { orderId: string; inboundCode: string; inboundOrderNo: string; overseasWarehouseId: string; overseasWarehouseName: string; availablePackages: number; skus: Array<{ skuCode: string; productName: string; availablePackages: number }> }
|
export interface DiscardCandidate { orderId: string; inboundCode: string; inboundOrderNo: string; overseasWarehouseId: string; overseasWarehouseName: string; availablePackages: number; skus: Array<{ skuCode: string; productName: string; availablePackages: number }> }
|
||||||
|
|
||||||
@@ -36,7 +48,7 @@ export function listRelabels(params: Record<string, unknown>) {
|
|||||||
return overseasApiRequest<PageResult<RelabelSummary>>({ method: 'GET', url: '/merchant/v1/last-leg/relabel-applications', params })
|
return overseasApiRequest<PageResult<RelabelSummary>>({ method: 'GET', url: '/merchant/v1/last-leg/relabel-applications', params })
|
||||||
}
|
}
|
||||||
export function getRelabel(relabelNo: string) {
|
export function getRelabel(relabelNo: string) {
|
||||||
return overseasApiRequest<Record<string, unknown>>({ method: 'GET', url: `/merchant/v1/last-leg/relabel-applications/${encodeURIComponent(relabelNo)}` })
|
return overseasApiRequest<RelabelDetail>({ method: 'GET', url: `/merchant/v1/last-leg/relabel-applications/${encodeURIComponent(relabelNo)}` })
|
||||||
}
|
}
|
||||||
export function createRelabel(payload: RelabelCreate) {
|
export function createRelabel(payload: RelabelCreate) {
|
||||||
return overseasApiRequest<Record<string, unknown>>({ method: 'POST', url: '/merchant/v1/last-leg/relabel-applications', data: payload })
|
return overseasApiRequest<Record<string, unknown>>({ method: 'POST', url: '/merchant/v1/last-leg/relabel-applications', data: payload })
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { ArrowLeft, Download, Eye, Plus, Search, Trash2, Upload } from '@lucide/
|
|||||||
import {
|
import {
|
||||||
createDiscard, createRelabel, createTransfer, getDiscard, getRelabel, getTransfer,
|
createDiscard, createRelabel, createTransfer, getDiscard, getRelabel, getTransfer,
|
||||||
listDiscardCandidates, listDiscards, listLastlegOrders, listRelabels, listTransfers,
|
listDiscardCandidates, listDiscards, listLastlegOrders, listRelabels, listTransfers,
|
||||||
|
type RelabelDetail,
|
||||||
} from '../api/warehouseServices'
|
} from '../api/warehouseServices'
|
||||||
|
|
||||||
type ServiceType = 'labeling' | 'transfer' | 'disposal' | 'relabel'
|
type ServiceType = 'labeling' | 'transfer' | 'disposal' | 'relabel'
|
||||||
@@ -31,6 +32,7 @@ const form = reactive({ customerNo: '', inboundNo: '', sourceWarehouse: '', ware
|
|||||||
const cargoRows = ref<CargoRow[]>([])
|
const cargoRows = ref<CargoRow[]>([])
|
||||||
const submittedRows = ref<Record<string, string>[]>([])
|
const submittedRows = ref<Record<string, string>[]>([])
|
||||||
const selectedDetail = ref<Record<string, string> | null>(null)
|
const selectedDetail = ref<Record<string, string> | null>(null)
|
||||||
|
const selectedRelabelDetail = ref<RelabelDetail | null>(null)
|
||||||
const discardCandidates = ref<import('../api/warehouseServices').DiscardCandidate[]>([])
|
const discardCandidates = ref<import('../api/warehouseServices').DiscardCandidate[]>([])
|
||||||
const selectedDiscardOrderId = ref('')
|
const selectedDiscardOrderId = ref('')
|
||||||
const discardCandidatesLoading = ref(false)
|
const discardCandidatesLoading = ref(false)
|
||||||
@@ -188,7 +190,9 @@ async function submit() {
|
|||||||
async function openDetail(value: Record<string, string>) {
|
async function openDetail(value: Record<string, string>) {
|
||||||
try {
|
try {
|
||||||
const detail = props.service === 'labeling' ? await getRelabel(value['0']) : props.service === 'disposal' ? await getDiscard(value['0']) : await getTransfer(value['0'])
|
const detail = props.service === 'labeling' ? await getRelabel(value['0']) : props.service === 'disposal' ? await getDiscard(value['0']) : await getTransfer(value['0'])
|
||||||
selectedDetail.value = { ...value, raw: JSON.stringify(detail) }; mode.value = 'detail'
|
selectedDetail.value = value
|
||||||
|
selectedRelabelDetail.value = props.service === 'labeling' ? detail as RelabelDetail : null
|
||||||
|
mode.value = 'detail'
|
||||||
} catch (error) { ElMessage.error(error instanceof Error ? error.message : '详情加载失败') }
|
} catch (error) { ElMessage.error(error instanceof Error ? error.message : '详情加载失败') }
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -253,11 +257,23 @@ async function openDetail(value: Record<string, string>) {
|
|||||||
</form>
|
</form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-else><div class="warehouse-breadcrumb"><button type="button" @click="mode = 'list'">{{ config.title }}</button><b>/</b><strong>订单详情</strong></div><div class="warehouse-page-heading"><h2>{{ config.title }}详情</h2><el-button @click="mode = 'list'"><ArrowLeft :size="16" />返回列表</el-button></div><div class="warehouse-card warehouse-form-section"><h3>订单概览</h3><div class="warehouse-detail-grid"><div v-for="(column, index) in config.columns.slice(0, -1)" :key="column"><span>{{ column }}</span><strong>{{ selectedDetail?.[String(index)] || '—' }}</strong></div></div></div></template>
|
<template v-else>
|
||||||
|
<div class="warehouse-breadcrumb"><button type="button" @click="mode = 'list'">{{ config.title }}</button><b>/</b><strong>订单详情</strong></div>
|
||||||
|
<div class="warehouse-page-heading"><h2>{{ config.title }}详情</h2><el-button @click="mode = 'list'"><ArrowLeft :size="16" />返回列表</el-button></div>
|
||||||
|
<div class="warehouse-card warehouse-form-section"><h3>订单概览</h3><div class="warehouse-detail-grid"><div v-for="(column, index) in config.columns.slice(0, -1)" :key="column"><span>{{ column }}</span><strong>{{ selectedDetail?.[String(index)] || '—' }}</strong></div></div></div>
|
||||||
|
<div v-if="props.service === 'labeling'" class="warehouse-card warehouse-form-section">
|
||||||
|
<h3>箱唛换标明细</h3>
|
||||||
|
<div class="warehouse-table-scroll"><table class="warehouse-relabel-detail-table"><thead><tr><th>我方箱唛</th><th>FBA 箱唛</th><th>商品 SKU</th><th>中文品名</th><th>FBA 货件编号</th><th>换标新 SKU</th><th>目的仓</th><th>贴标要求</th><th>备注</th></tr></thead><tbody>
|
||||||
|
<tr v-for="item in selectedRelabelDetail?.items || []" :key="item.id"><td><strong>{{ item.cartonMark || '—' }}</strong></td><td><strong>{{ item.fbaCartonMark || '—' }}</strong></td><td>{{ item.skuCode || '—' }}</td><td>{{ item.productNameZh || '—' }}</td><td>{{ item.shipmentNo || '—' }}</td><td>{{ item.newSkuCode || '—' }}</td><td>{{ warehouseDisplay(item.destinationWarehouseId) }}</td><td>{{ item.labelRequirement || '—' }}</td><td>{{ item.remark || '—' }}</td></tr>
|
||||||
|
<tr v-if="!selectedRelabelDetail?.items?.length"><td colspan="9"><div class="warehouse-empty">暂无箱唛换标明细</div></td></tr>
|
||||||
|
</tbody></table></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.warehouse-service-page{color:#25324a}.warehouse-breadcrumb{display:flex;align-items:center;gap:9px;margin:0 0 14px;color:#9aa3b2;font-size:12px}.warehouse-breadcrumb b{font-weight:400}.warehouse-breadcrumb strong{color:#606b7c}.warehouse-breadcrumb button{padding:0;border:0;background:transparent;color:#4376b8;cursor:pointer}.warehouse-page-heading{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px}.warehouse-page-heading h2{margin:0;color:#17233a;font-size:22px;letter-spacing:0}.warehouse-card{margin-bottom:12px;border:1px solid #e7ebf1;border-radius:4px;background:#fff;box-shadow:0 1px 3px rgba(25,42,70,.04)}.warehouse-filter-card{padding:20px 22px 16px}.warehouse-filter-grid{display:grid;grid-template-columns:repeat(4,minmax(180px,1fr));gap:16px 20px}.warehouse-filter-grid label,.warehouse-form-grid label{display:flex;min-width:0;flex-direction:column;gap:7px}.warehouse-filter-grid label>span,.warehouse-form-grid label>span{color:#596579;font-size:12px}.warehouse-filter-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:18px}.warehouse-table-card{overflow:hidden}.warehouse-table-scroll{overflow-x:auto}table{width:100%;min-width:940px;border-collapse:collapse;font-size:12px}th{height:44px;padding:0 14px;border-bottom:1px solid #e8edf3;background:#f7f9fc;color:#4d5a6e;font-weight:650;text-align:left;white-space:nowrap}td{height:48px;padding:8px 14px;border-bottom:1px solid #eef1f5;color:#526176;white-space:nowrap}.warehouse-empty{display:grid;height:150px;color:#a0a9b7;place-items:center}.warehouse-link,.warehouse-delete{display:inline-flex;align-items:center;gap:5px;padding:4px;border:0;background:transparent;color:#2176d2;cursor:pointer}.warehouse-delete{color:#d64545}.warehouse-pagination{display:flex;align-items:center;justify-content:flex-end;gap:8px;padding:14px 18px;color:#778398;font-size:12px}.warehouse-pagination span{margin-right:8px}.warehouse-page-number{width:28px;height:28px;border:1px solid #2176d2;border-radius:3px;background:#2176d2;color:#fff}.warehouse-form-section{padding:22px}.warehouse-form-section h3{margin:0 0 18px;padding-bottom:12px;border-bottom:1px solid #edf0f4;color:#26364f;font-size:15px;letter-spacing:0}.warehouse-form-grid{display:grid;grid-template-columns:repeat(2,minmax(240px,1fr));gap:18px 28px}.warehouse-form-grid i{margin-right:3px;color:#e24b4b;font-style:normal}.warehouse-span-2{grid-column:1/-1}.warehouse-section-heading{display:flex;align-items:center;justify-content:space-between}.warehouse-section-heading h3{flex:1}.warehouse-edit-table td{padding:9px 10px}.warehouse-edit-table :deep(.el-input-number){width:130px}.warehouse-hint{margin:12px 0 0;color:#8792a2;font-size:12px}.warehouse-submit-bar{display:flex;justify-content:center;gap:10px;padding:12px 0 30px}.warehouse-detail-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:24px}.warehouse-detail-grid div{display:flex;flex-direction:column;gap:7px}.warehouse-detail-grid span{color:#8a95a5;font-size:12px}.warehouse-detail-grid strong{color:#334157;font-size:13px}:deep(.el-button){border-radius:4px}:deep(.el-button span){display:inline-flex;align-items:center;gap:6px}:deep(.el-select),:deep(.el-date-editor.el-input){width:100%}@media(max-width:1100px){.warehouse-filter-grid{grid-template-columns:repeat(2,1fr)}.warehouse-detail-grid{grid-template-columns:repeat(2,1fr)}}
|
.warehouse-service-page{color:#25324a}.warehouse-breadcrumb{display:flex;align-items:center;gap:9px;margin:0 0 14px;color:#9aa3b2;font-size:12px}.warehouse-breadcrumb b{font-weight:400}.warehouse-breadcrumb strong{color:#606b7c}.warehouse-breadcrumb button{padding:0;border:0;background:transparent;color:#4376b8;cursor:pointer}.warehouse-page-heading{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px}.warehouse-page-heading h2{margin:0;color:#17233a;font-size:22px;letter-spacing:0}.warehouse-card{margin-bottom:12px;border:1px solid #e7ebf1;border-radius:4px;background:#fff;box-shadow:0 1px 3px rgba(25,42,70,.04)}.warehouse-filter-card{padding:20px 22px 16px}.warehouse-filter-grid{display:grid;grid-template-columns:repeat(4,minmax(180px,1fr));gap:16px 20px}.warehouse-filter-grid label,.warehouse-form-grid label{display:flex;min-width:0;flex-direction:column;gap:7px}.warehouse-filter-grid label>span,.warehouse-form-grid label>span{color:#596579;font-size:12px}.warehouse-filter-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:18px}.warehouse-table-card{overflow:hidden}.warehouse-table-scroll{overflow-x:auto}table{width:100%;min-width:940px;border-collapse:collapse;font-size:12px}th{height:44px;padding:0 14px;border-bottom:1px solid #e8edf3;background:#f7f9fc;color:#4d5a6e;font-weight:650;text-align:left;white-space:nowrap}td{height:48px;padding:8px 14px;border-bottom:1px solid #eef1f5;color:#526176;white-space:nowrap}.warehouse-empty{display:grid;height:150px;color:#a0a9b7;place-items:center}.warehouse-link,.warehouse-delete{display:inline-flex;align-items:center;gap:5px;padding:4px;border:0;background:transparent;color:#2176d2;cursor:pointer}.warehouse-delete{color:#d64545}.warehouse-pagination{display:flex;align-items:center;justify-content:flex-end;gap:8px;padding:14px 18px;color:#778398;font-size:12px}.warehouse-pagination span{margin-right:8px}.warehouse-page-number{width:28px;height:28px;border:1px solid #2176d2;border-radius:3px;background:#2176d2;color:#fff}.warehouse-form-section{padding:22px}.warehouse-form-section h3{margin:0 0 18px;padding-bottom:12px;border-bottom:1px solid #edf0f4;color:#26364f;font-size:15px;letter-spacing:0}.warehouse-form-grid{display:grid;grid-template-columns:repeat(2,minmax(240px,1fr));gap:18px 28px}.warehouse-form-grid i{margin-right:3px;color:#e24b4b;font-style:normal}.warehouse-span-2{grid-column:1/-1}.warehouse-section-heading{display:flex;align-items:center;justify-content:space-between}.warehouse-section-heading h3{flex:1}.warehouse-edit-table td{padding:9px 10px}.warehouse-edit-table :deep(.el-input-number){width:130px}.warehouse-hint{margin:12px 0 0;color:#8792a2;font-size:12px}.warehouse-submit-bar{display:flex;justify-content:center;gap:10px;padding:12px 0 30px}.warehouse-detail-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:24px}.warehouse-detail-grid div{display:flex;flex-direction:column;gap:7px}.warehouse-detail-grid span{color:#8a95a5;font-size:12px}.warehouse-detail-grid strong{color:#334157;font-size:13px}:deep(.el-button){border-radius:4px}:deep(.el-button span){display:inline-flex;align-items:center;gap:6px}:deep(.el-select),:deep(.el-date-editor.el-input){width:100%}@media(max-width:1100px){.warehouse-filter-grid{grid-template-columns:repeat(2,1fr)}.warehouse-detail-grid{grid-template-columns:repeat(2,1fr)}}
|
||||||
.warehouse-hidden-input{display:none}.warehouse-label-table{min-width:1320px}.warehouse-attachment-tip{margin:10px 0 12px;color:#7d8797;font-size:12px}.warehouse-mark-mapping{display:flex;flex-wrap:wrap;gap:8px;margin:4px 0 8px;padding:12px;border:1px solid #dce7f5;border-radius:5px;background:#f7faff}.warehouse-mark-mapping strong{width:100%;color:#34445c}.warehouse-mark-mapping span{padding:5px 9px;border-radius:3px;background:#eaf2fc;color:#3e6593;font-size:12px}
|
.warehouse-hidden-input{display:none}.warehouse-label-table{min-width:1320px}.warehouse-attachment-tip{margin:10px 0 12px;color:#7d8797;font-size:12px}.warehouse-mark-mapping{display:flex;flex-wrap:wrap;gap:8px;margin:4px 0 8px;padding:12px;border:1px solid #dce7f5;border-radius:5px;background:#f7faff}.warehouse-mark-mapping strong{width:100%;color:#34445c}.warehouse-mark-mapping span{padding:5px 9px;border-radius:3px;background:#eaf2fc;color:#3e6593;font-size:12px}
|
||||||
|
.warehouse-relabel-detail-table{min-width:1420px}.warehouse-relabel-detail-table td strong{color:#253f67}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -36,3 +36,13 @@ test('商品 SKU 在贴标模板和明细中为选填', () => {
|
|||||||
assert.match(view, /商品 SKU<span v-if="props\.service !== 'labeling'"> \*<\/span>/)
|
assert.match(view, /商品 SKU<span v-if="props\.service !== 'labeling'"> \*<\/span>/)
|
||||||
assert.match(api, /skuCode\?: string; productNameZh/)
|
assert.match(api, /skuCode\?: string; productNameZh/)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('贴标申请详情展示逐箱箱唛换标关系', () => {
|
||||||
|
assert.match(api, /export interface RelabelDetail/)
|
||||||
|
assert.match(api, /return overseasApiRequest<RelabelDetail>/)
|
||||||
|
assert.match(view, /<h3>箱唛换标明细<\/h3>/)
|
||||||
|
assert.match(view, /item\.cartonMark \|\| '—'/)
|
||||||
|
assert.match(view, /item\.fbaCartonMark \|\| '—'/)
|
||||||
|
assert.match(view, /item\.shipmentNo \|\| '—'/)
|
||||||
|
assert.match(view, /item\.newSkuCode \|\| '—'/)
|
||||||
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user