diff --git a/src/modules/container-loading/pages/GlobalSmartLoadingView.test.ts b/src/modules/container-loading/pages/GlobalSmartLoadingView.test.ts
index 004e8ed8..90e10c0b 100644
--- a/src/modules/container-loading/pages/GlobalSmartLoadingView.test.ts
+++ b/src/modules/container-loading/pages/GlobalSmartLoadingView.test.ts
@@ -1,4 +1,4 @@
-import ElementPlus, { ElMessage, ElMessageBox } from 'element-plus'
+import ElementPlus, { ElInputNumber, ElMessage, ElMessageBox } from 'element-plus'
import { AxiosError } from 'axios'
import { createPinia, setActivePinia } from 'pinia'
import { flushPromises, mount } from '@vue/test-utils'
@@ -71,10 +71,28 @@ describe('GlobalSmartLoadingView', () => {
expect(listSmartLoadingCandidates).toHaveBeenCalledWith(container.id, container.warehouseId)
expect(wrapper.text()).toContain('候选入库单与货物')
expect(wrapper.text()).toContain('美森正班海卡包税')
- expect(wrapper.text()).toContain('ORD-2')
- expect(wrapper.text()).toContain('CB-1 装柜方案')
- expect(wrapper.text()).toContain('LP-99')
- expect(wrapper.text()).toContain('ORD-1')
+ expect(wrapper.text()).toContain('IN-2')
+ expect(wrapper.text()).toContain('MSCU-1 装柜方案')
+ expect(wrapper.text()).not.toContain('LP-99')
+ expect(wrapper.text()).toContain('IN-1')
+ expect(wrapper.text()).not.toContain('ORD-1')
+ expect(wrapper.text()).not.toContain('ORD-2')
+ })
+
+ it('shows one user-facing container number and hides internal manual or split references', async () => {
+ vi.mocked(listContainers).mockResolvedValue({
+ records: [{ ...container, cabinetNo: 'CAB-20260814-01', containerNo: 'SPLIT-814022117898chain1' }],
+ page: 1,
+ size: 100,
+ total: 1,
+ pages: 1,
+ })
+ const wrapper = mount(GlobalSmartLoadingView, { global: { plugins: [ElementPlus] } })
+ await flushPromises()
+
+ expect(wrapper.text()).toContain('CAB-20260814-01')
+ expect(wrapper.text()).not.toContain('SPLIT-814022117898chain1')
+ expect(wrapper.text()).not.toContain('LP-99')
})
it('groups containers by channel and reloads candidates when the channel changes', async () => {
@@ -83,6 +101,7 @@ describe('GlobalSmartLoadingView', () => {
id: '9007199254740998',
planId: '9007199254740999',
cabinetNo: 'CB-2',
+ containerNo: 'MSCU-2',
channelCode: 'HDHK',
channelName: '合德海卡包税',
}
@@ -92,8 +111,9 @@ describe('GlobalSmartLoadingView', () => {
await flushPromises()
expect(wrapper.findAll('.container-option')).toHaveLength(1)
- expect(wrapper.text()).toContain('CB-1')
- expect(wrapper.text()).not.toContain('CB-2')
+ expect(wrapper.text()).toContain('MSCU-1')
+ expect(wrapper.text()).not.toContain('MSCU-2')
+ expect(wrapper.text()).not.toContain('个柜次')
const tab = wrapper.findAll('[role="tab"]').find((item) => item.text().includes('合德海卡包税'))
expect(tab).toBeDefined()
@@ -101,8 +121,8 @@ describe('GlobalSmartLoadingView', () => {
await flushPromises()
expect(wrapper.findAll('.container-option')).toHaveLength(1)
- expect(wrapper.text()).toContain('CB-2')
- expect(wrapper.text()).not.toContain('CB-1')
+ expect(wrapper.text()).toContain('MSCU-2')
+ expect(wrapper.text()).not.toContain('MSCU-1')
expect(listSmartLoadingCandidates).toHaveBeenLastCalledWith(other.id, other.warehouseId)
})
@@ -129,16 +149,14 @@ describe('GlobalSmartLoadingView', () => {
expect(wrapper.findAll('button[aria-label="列设置"]')).toHaveLength(0)
})
- it('keeps unsupported prototype filters out of the real workbench', async () => {
+ it('keeps only customer, inbound code and destination warehouse filters', async () => {
const wrapper = mount(GlobalSmartLoadingView, { global: { plugins: [ElementPlus] } })
await flushPromises()
- const statusField = wrapper.findComponent(QueryToolbar).props('fields')
- .find((field: { key: string }) => field.key === 'status')
- expect(statusField?.options).toEqual([
- { label: '待装柜', value: 'WAIT_LOADING' },
- { label: '预装柜中', value: 'EDITING' },
- { label: '拣货中', value: 'LOADING' },
+ const fields = wrapper.findComponent(QueryToolbar).props('fields') as Array<{ key: string; options?: Array<{ label: string; value: string }> }>
+ expect(fields.map((field) => field.key)).toEqual(['customerId', 'inboundCode', 'destinationWarehouse'])
+ expect(fields.find((field) => field.key === 'destinationWarehouse')?.options).toEqual([
+ { label: 'LAX9', value: '9' },
])
expect(wrapper.text()).not.toContain('税率')
@@ -152,11 +170,11 @@ describe('GlobalSmartLoadingView', () => {
await flushPromises()
expect(getSmartLoadingPlanByBooking).toHaveBeenCalledWith(container.id)
- expect(wrapper.text()).toContain('CB-1 装柜方案')
+ expect(wrapper.text()).toContain('MSCU-1 装柜方案')
})
- it('does not overwrite the container status when selecting it', async () => {
- const waiting = { ...container, id: '9007199254740995', planId: '9007199254740996', cabinetNo: 'CB-WAIT', planStatus: 'WAIT_LOADING' as const }
+ it('keeps waiting and editing empty containers without exposing their status labels', async () => {
+ const waiting = { ...container, id: '9007199254740995', planId: '9007199254740996', cabinetNo: 'CB-WAIT', containerNo: null, planStatus: 'WAIT_LOADING' as const }
vi.mocked(listContainers).mockResolvedValue({ records: [container, waiting], page: 1, size: 100, total: 2, pages: 1 })
vi.mocked(getSmartLoadingPlanByBooking).mockImplementation(async (bookingId) => (
bookingId === waiting.id
@@ -167,31 +185,27 @@ describe('GlobalSmartLoadingView', () => {
await flushPromises()
const waitingOption = wrapper.findAll('.container-option').find((item) => item.text().includes('CB-WAIT'))!
- expect(waitingOption.text()).toContain('待装柜')
+ expect(waitingOption.text()).toContain('CB-WAIT')
+ expect(waitingOption.text()).not.toContain('待装柜')
await waitingOption.trigger('click')
await flushPromises()
expect(getSmartLoadingPlanByBooking).toHaveBeenCalledWith(waiting.id)
- expect(waitingOption.text()).toContain('待装柜')
+ expect(waitingOption.text()).toContain('CB-WAIT')
expect(waitingOption.text()).not.toContain('拣货中')
})
- it('keeps picking containers editable while hiding the push action', async () => {
+ it('excludes picking containers from the empty-container workbench', async () => {
const pushed = { ...container, id: '9007199254740995', planId: '9007199254740996', cabinetNo: 'CB-2', planStatus: 'LOADING' as const }
- const pickingPlan = { ...plan, bookingId: pushed.id, status: 'LOADING' as const }
vi.mocked(listContainers).mockResolvedValue({ records: [pushed], page: 1, size: 100, total: 1, pages: 1 })
- vi.mocked(getSmartLoadingPlanByBooking).mockResolvedValue(pickingPlan)
const wrapper = mount(GlobalSmartLoadingView, { global: { plugins: [ElementPlus] } })
await flushPromises()
- expect(getSmartLoadingPlanByBooking).toHaveBeenCalledWith(pushed.id)
- expect(listSmartLoadingCandidates).toHaveBeenCalledWith(pushed.id, pushed.warehouseId)
- expect(wrapper.text()).toContain('CB-2')
- expect(wrapper.text()).toContain('拣货中')
- expect(wrapper.text()).toContain('智能推荐')
- expect(wrapper.text()).toContain('加入')
- expect(wrapper.findAll('button').some((item) => item.text().trim() === '推送预装')).toBe(false)
+ expect(getSmartLoadingPlanByBooking).not.toHaveBeenCalled()
+ expect(listSmartLoadingCandidates).not.toHaveBeenCalled()
+ expect(wrapper.findAll('.container-option')).toHaveLength(0)
+ expect(wrapper.text()).not.toContain('CB-2')
})
it('hides completed containers from the smart loading workbench', async () => {
@@ -206,6 +220,7 @@ describe('GlobalSmartLoadingView', () => {
})
it('refreshes the latest plan after A0409 without losing the selected container', async () => {
+ const warningMessage = vi.spyOn(ElMessage, 'warning').mockImplementation(() => undefined as never)
const wrapper = mount(GlobalSmartLoadingView, { global: { plugins: [ElementPlus] } })
await flushPromises()
vi.mocked(getSmartLoadingPlanByBooking).mockResolvedValue({ ...plan, version: 3 })
@@ -224,16 +239,12 @@ describe('GlobalSmartLoadingView', () => {
expect(recommendSmartLoading).toHaveBeenCalledWith(plan.id, 2)
expect(getSmartLoadingPlanByBooking).toHaveBeenCalledTimes(2)
- expect(wrapper.text()).toContain('版本 3')
- expect(wrapper.text()).toContain('已刷新最新版本')
- expect(wrapper.text()).toContain('request-1')
+ expect(warningMessage).toHaveBeenCalledWith('方案已被其他人修改,已刷新最新版本,请重新确认后提交')
+ expect(wrapper.text()).not.toContain('装柜操作失败')
+ expect(wrapper.text()).not.toContain('request-1')
})
it('shows a picking-specific message when a picked order cannot be removed', async () => {
- const loadingContainer = { ...container, planStatus: 'LOADING' as const }
- const loadingPlan = { ...plan, status: 'LOADING' as const }
- vi.mocked(listContainers).mockResolvedValue({ records: [loadingContainer], page: 1, size: 100, total: 1, pages: 1 })
- vi.mocked(getSmartLoadingPlanByBooking).mockResolvedValue(loadingPlan)
vi.mocked(removeSmartLoadingItem).mockRejectedValue(new AxiosError(
'conflict',
'ERR_BAD_REQUEST',
@@ -253,15 +264,80 @@ describe('GlobalSmartLoadingView', () => {
expect(removeSmartLoadingItem).toHaveBeenCalled()
expect(errorMessage).toHaveBeenCalledWith('该订单在拣货中不许删除')
- expect(wrapper.text()).toContain('该订单在拣货中不许删除')
+ expect(wrapper.text()).not.toContain('装柜操作失败')
+ expect(wrapper.text()).not.toContain('该订单在拣货中不许删除')
+ })
+
+ it('removes every item with the latest returned plan version', async () => {
+ const secondItem = { ...plan.items[0], id: '102', inboundDetailId: '4', inboundCode: 'IN-2' }
+ const initialPlan = { ...plan, items: [plan.items[0], secondItem] }
+ const afterFirst = { ...plan, version: 3, items: [secondItem] }
+ const emptyPlan = { ...plan, version: 4, items: [] }
+ vi.mocked(getSmartLoadingPlanByBooking).mockResolvedValueOnce(initialPlan).mockResolvedValue(emptyPlan)
+ vi.mocked(removeSmartLoadingItem).mockResolvedValueOnce(afterFirst).mockResolvedValueOnce(emptyPlan)
+ vi.spyOn(ElMessageBox, 'confirm').mockResolvedValue('confirm' as never)
+
+ const wrapper = mount(GlobalSmartLoadingView, { global: { plugins: [ElementPlus] } })
+ await flushPromises()
+ const removeAllButton = wrapper.findAll('button').find((button) => button.text().includes('全部移除'))
+ expect(removeAllButton).toBeDefined()
+ await removeAllButton!.trigger('click')
+ await flushPromises()
+
+ expect(removeSmartLoadingItem).toHaveBeenNthCalledWith(1, plan.id, plan.items[0].id, 2, 1)
+ expect(removeSmartLoadingItem).toHaveBeenNthCalledWith(2, plan.id, secondItem.id, 3, 1)
+ expect(wrapper.text()).toContain('当前柜次暂无已装货物')
+ })
+
+ it('limits adjusted package count to the assigned count plus remaining availability', async () => {
+ vi.mocked(listSmartLoadingCandidates).mockResolvedValue([{ accountId: '1', inboundId: '2', inboundDetailId: '3', orderId: '4', orderNo: 'ORD-1', inboundCode: 'IN-1', warehouseId: '8', channelCode: 'ZBYHK', channelName: '美森正班海卡包税', destinationWarehouseId: '9', destinationWarehouseCode: 'LAX9', destinationWarehouseName: 'LAX9', customerName: '示例企业', goodsName: '服装', availablePackageCount: 4, unitWeightKg: 10, unitVolumeCbm: 0.2 }])
+ const wrapper = mount(GlobalSmartLoadingView, { global: { plugins: [ElementPlus] } })
+ await flushPromises()
+
+ const maxima = wrapper.findAllComponents(ElInputNumber).map((input) => input.props('max'))
+ expect(maxima).toContain(10)
})
it('uses bordered assignment and adjustment actions at narrow widths', () => {
const source = readFileSync(resolve(process.cwd(), 'src/modules/container-loading/pages/GlobalSmartLoadingView.vue'), 'utf8')
expect(source).toContain('size="small"')
expect(source).toContain('type="danger" plain')
+ expect(source).toContain(':max="adjustmentMax(row)"')
expect(source).not.toContain('link type="danger"')
expect(source).toContain('@media (max-width: 720px)')
expect(source.match(/ {
+ const source = readFileSync(resolve(process.cwd(), 'src/modules/container-loading/pages/GlobalSmartLoadingView.vue'), 'utf8')
+
+ expect(source).toContain('height: clamp(520px, 68vh, 720px); min-height: 0;')
+ expect(source).toContain('.dispatch-pane { display: flex; min-width: 0; min-height: 0; flex-direction: column; }')
+ expect(source).toContain('.candidate-pane :deep(.data-table),.plan-pane :deep(.data-table) { min-height: 0; flex: 1; }')
+ expect(source).toContain('.container-list { display: grid; min-height: 0; flex: 1;')
+ expect(source).toContain('grid-auto-rows: max-content;')
+ expect(source).toContain('overflow-wrap: anywhere;')
+ expect(source).toContain('.candidate-pane,.plan-pane { height: min(68vh, 560px); min-height: 420px; }')
+ expect(source).toContain('.container-pane { max-height: min(58vh, 460px); }')
+ })
+
+ it('uses overflow-aware channel tabs with a compact right-aligned summary', () => {
+ const source = readFileSync(resolve(process.cwd(), 'src/modules/container-loading/pages/GlobalSmartLoadingView.vue'), 'utf8')
+
+ expect(source).toContain('候选货物')
+ expect(source).toContain('空柜')
+ expect(source).toContain('已装')
+ expect(source).toContain('总重量')
+ expect(source).toContain('总体积')
+ expect(source).toContain('.channel-tabs :deep(.el-tabs__content) { display: none; }')
+ expect(source).not.toContain('class="summary-band"')
+ expect(source).toContain('class="capacity-grid"')
+ expect(source).toContain('智能推荐')
+ expect(source).toContain('推送预装')
+ })
})
diff --git a/src/modules/container-loading/pages/GlobalSmartLoadingView.vue b/src/modules/container-loading/pages/GlobalSmartLoadingView.vue
index 19d45c60..1e790693 100644
--- a/src/modules/container-loading/pages/GlobalSmartLoadingView.vue
+++ b/src/modules/container-loading/pages/GlobalSmartLoadingView.vue
@@ -46,13 +46,12 @@ const selectionLoading = ref(false)
const mutating = ref(false)
const loadError = ref(null)
const selectionError = ref(null)
-const mutationError = ref(null)
const noDraft = ref(false)
const assignOpen = ref(false)
const selectedCandidate = ref(null)
const assignForm = reactive({ packageCount: 1 })
const quantityDrafts = reactive>({})
-const query = ref({ customerId: '', orderKeyword: '', containerKeyword: '', status: '' })
+const query = ref({ customerId: '', inboundCode: '', destinationWarehouse: '' })
const appliedQuery = ref({ ...query.value })
let selectionRequest = 0
@@ -62,15 +61,12 @@ const canDelete = computed(() => access.can('platform:firstleg:smart-loading:del
const canPush = computed(() => access.can('platform:firstleg:smart-loading:push'))
const selectedContainer = computed(() => containers.value.find((item) => item.id === selectedContainerId.value) || null)
const channelTabs = computed(() => {
- const channels = new Map()
+ const channels = new Map()
for (const item of containers.value) {
if (!['WAIT_LOADING', 'EDITING'].includes(item.planStatus) || !item.channelCode) continue
- const current = channels.get(item.channelCode)
- if (current) current.containerCount += 1
- else channels.set(item.channelCode, {
+ if (!channels.has(item.channelCode)) channels.set(item.channelCode, {
code: item.channelCode,
name: item.channelName || item.channelCode,
- containerCount: 1,
})
}
return [...channels.values()]
@@ -88,49 +84,45 @@ const volumePercent = computed(() => volumeLimit.value ? totalVolume.value / vol
const weightPercent = computed(() => weightLimit.value ? totalWeight.value / weightLimit.value * 100 : 0)
const displayedVolumePercent = computed(() => percentage(volumePercent.value))
const displayedWeightPercent = computed(() => percentage(weightPercent.value))
-
+const destinationWarehouseOptions = computed(() => {
+ const options = new Map()
+ for (const item of candidates.value) {
+ const value = destinationWarehouseKey(item)
+ if (value) options.set(value, item.destinationWarehouseName || item.destinationWarehouseCode || value)
+ }
+ return [...options].map(([value, label]) => ({ label, value }))
+})
const queryFields = computed(() => [
{ key: 'customerId', type: 'select', label: '客户', placeholder: '全部客户', width: 220, options: customers.value.filter((customer) => customer.status === 'ACTIVE').map((customer) => ({ label: customer.tenantName, value: String(customer.id) })), props: { filterable: true, loading: customersLoading.value } },
- { key: 'orderKeyword', type: 'input', label: '订单或货物', placeholder: '订单号、入库单、货物', width: 250 },
- { key: 'containerKeyword', type: 'input', label: '柜号', placeholder: '请输入柜号', width: 230 },
- { key: 'status', type: 'select', label: '柜次状态', width: 160, options: [
- { label: '待装柜', value: 'WAIT_LOADING' },
- { label: '预装柜中', value: 'EDITING' },
- ] },
+ { key: 'inboundCode', type: 'input', label: '入仓码', placeholder: '请输入入仓码', width: 240 },
+ { key: 'destinationWarehouse', type: 'select', label: '目的仓', placeholder: '全部目的仓', width: 200, options: destinationWarehouseOptions.value, props: { filterable: true } },
])
-const filteredContainers = computed(() => {
- const keyword = String(appliedQuery.value.containerKeyword || '').trim().toLowerCase()
- const status = String(appliedQuery.value.status || '')
- return containers.value.filter((item) => {
- if (!['WAIT_LOADING', 'EDITING'].includes(item.planStatus)) return false
- if (!activeChannelCode.value || item.channelCode !== activeChannelCode.value) return false
- if (status && item.planStatus !== status) return false
- if (!keyword) return true
- return displayContainerNo(item).toLowerCase().includes(keyword)
- })
-})
+const filteredContainers = computed(() => containers.value.filter((item) => (
+ ['WAIT_LOADING', 'EDITING'].includes(item.planStatus)
+ && Boolean(activeChannelCode.value)
+ && item.channelCode === activeChannelCode.value
+)))
const filteredCandidates = computed(() => {
const customerId = String(appliedQuery.value.customerId || '')
- const keyword = String(appliedQuery.value.orderKeyword || '').trim().toLowerCase()
+ const inboundCode = String(appliedQuery.value.inboundCode || '').trim().toLowerCase()
+ const destinationWarehouse = String(appliedQuery.value.destinationWarehouse || '')
return candidates.value.filter((item) => {
if (customerId && item.accountId !== customerId) return false
- if (!keyword) return true
- return [item.orderNo, item.inboundCode, item.goodsName]
- .some((value) => String(value || '').toLowerCase().includes(keyword))
+ if (destinationWarehouse && destinationWarehouseKey(item) !== destinationWarehouse) return false
+ return !inboundCode || String(item.inboundCode || '').toLowerCase().includes(inboundCode)
})
})
function preferredContainerId() {
const visible = filteredContainers.value
- if (String(appliedQuery.value.status || '').trim()) return visible[0]?.id || ''
return visible.find((item) => item.planStatus === 'EDITING')?.id
|| visible.find((item) => item.planStatus === 'WAIT_LOADING')?.id || visible[0]?.id || ''
}
const candidateColumns: DataTableColumn[] = [
{ key: 'actions', label: '操作', width: 92, fixed: 'left', slotName: 'actions' },
- { key: 'order', label: '订单/入库单', minWidth: 170, slotName: 'order' },
+ { key: 'order', label: '入仓码', minWidth: 170, slotName: 'order' },
{ key: 'goodsName', prop: 'goodsName', label: '货物', minWidth: 150 },
{ key: 'customerName', prop: 'customerName', label: '客户', minWidth: 140 },
{ key: 'availablePackageCount', prop: 'availablePackageCount', label: '可用箱数', width: 100 },
@@ -139,7 +131,7 @@ const candidateColumns: DataTableColumn[] = [
]
const itemColumns: DataTableColumn[] = [
{ key: 'actions', label: '操作', width: 170, fixed: 'left', slotName: 'actions' },
- { key: 'order', label: '订单/入库单', minWidth: 170, slotName: 'order' },
+ { key: 'order', label: '入仓码', minWidth: 170, slotName: 'order' },
{ key: 'goods', label: '货物', minWidth: 160, slotName: 'goods' },
{ key: 'packageCount', label: '分配箱数', width: 140, slotName: 'packageCount' },
{ key: 'volumeCbm', label: '体积', width: 105, slotName: 'volume' },
@@ -152,6 +144,14 @@ function formatNumber(value: number, digits = 3) {
function percentage(value: number) { return Number.isFinite(value) ? Number(Math.max(value, 0).toFixed(2)) : 0 }
function candidateRow(source: object) { return source as SmartLoadingCandidate }
function itemRow(source: object) { return source as SmartLoadingItem }
+function adjustmentMax(source: object) {
+ const item = itemRow(source)
+ const remaining = candidates.value.find((candidate) => candidate.inboundDetailId === item.inboundDetailId)?.availablePackageCount || 0
+ return Math.max(1, item.packageCount + remaining)
+}
+function destinationWarehouseKey(candidate: SmartLoadingCandidate) {
+ return candidate.destinationWarehouseId || candidate.destinationWarehouseCode || candidate.destinationWarehouseName || ''
+}
function displayContainerNo(container: ContainerBookingResource | null | undefined) {
if (!container) return '柜号待生成'
const actual = String(container.containerNo || '').trim()
@@ -250,14 +250,12 @@ async function loadCustomers() {
async function selectContainer(containerId: string) {
if (selectedContainerId.value === containerId) return
selectedContainerId.value = containerId
- mutationError.value = null
await loadSelectedData()
}
async function selectChannel(channelCode: string) {
if (activeChannelCode.value === channelCode) return
activeChannelCode.value = channelCode
selectedContainerId.value = preferredContainerId()
- mutationError.value = null
await loadSelectedData()
}
async function applyFilters(model: QueryModel) {
@@ -281,6 +279,10 @@ function openAssign(source: object) {
}
async function assign() {
if (!plan.value || !selectedCandidate.value || assignForm.packageCount < 1) return
+ if (assignForm.packageCount > selectedCandidate.value.availablePackageCount) {
+ ElMessage.warning(`本次最多可分配 ${selectedCandidate.value.availablePackageCount} 箱`)
+ return
+ }
await mutate(async () => {
acceptPlan(await assignSmartLoadingItem(plan.value!.id, {
inboundId: selectedCandidate.value!.inboundId,
@@ -289,6 +291,7 @@ async function assign() {
expectedVersion: plan.value!.version,
}))
assignOpen.value = false
+ await loadSelectedData()
ElMessage.success('货物已加入当前柜次')
}, '分配货物失败', { preserveAssign: true })
}
@@ -296,6 +299,7 @@ async function recommend() {
if (!plan.value) return
await mutate(async () => {
acceptPlan(await recommendSmartLoading(plan.value!.id, plan.value!.version))
+ await loadSelectedData()
ElMessage.success('智能推荐已生成')
}, '智能推荐失败')
}
@@ -304,23 +308,46 @@ async function adjust(source: object) {
if (!plan.value) return
const count = Number(quantityDrafts[item.id])
if (!Number.isInteger(count) || count < 1) { ElMessage.warning('分配箱数必须为正整数'); return }
+ const max = adjustmentMax(item)
+ if (count > max) { ElMessage.warning(`该货物最多可分配 ${max} 箱`); return }
await mutate(async () => {
acceptPlan(await adjustSmartLoadingItem(plan.value!.id, item.id, count, plan.value!.version, item.version))
+ await loadSelectedData()
ElMessage.success('箱数已调整')
}, '调整箱数失败', { preserveDrafts: { ...quantityDrafts } })
}
async function remove(source: object) {
const item = itemRow(source)
if (!plan.value) return
- const confirmed = await ElMessageBox.confirm(`确认从当前柜次移除“${item.productNameZh || item.orderNo || item.id}”吗?`, '移除装柜明细', {
+ const confirmed = await ElMessageBox.confirm(`确认从当前柜次移除“${item.productNameZh || item.inboundCode || '该货物'}”吗?`, '移除装柜明细', {
type: 'warning', confirmButtonText: '移除', cancelButtonText: '取消',
}).catch(() => false)
if (!confirmed || !plan.value) return
await mutate(async () => {
acceptPlan(await removeSmartLoadingItem(plan.value!.id, item.id, plan.value!.version, item.version))
+ await loadSelectedData()
ElMessage.success('装柜明细已移除')
}, '移除装柜明细失败', { pickingConflict: true })
}
+async function removeAll() {
+ if (!plan.value?.items.length) return
+ const itemCount = plan.value.items.length
+ const confirmed = await ElMessageBox.confirm(`确认移除当前方案的全部 ${itemCount} 条装柜明细吗?`, '全部移除', {
+ type: 'warning', confirmButtonText: '全部移除', cancelButtonText: '取消',
+ }).catch(() => false)
+ if (!confirmed || !plan.value) return
+ await mutate(async () => {
+ let current = plan.value!
+ for (const original of [...current.items]) {
+ const item = current.items.find((value) => value.id === original.id)
+ if (!item) continue
+ current = await removeSmartLoadingItem(current.id, item.id, current.version, item.version)
+ acceptPlan(current)
+ }
+ await loadSelectedData()
+ ElMessage.success(`已移除全部 ${itemCount} 条装柜明细`)
+ }, '全部移除失败', { pickingConflict: true })
+}
async function pushPreload() {
if (!plan.value) return
const confirmed = await ElMessageBox.confirm('推送后当前方案进入装柜流程,不能继续调整。确认推送预装清单?', '推送预装清单', {
@@ -339,7 +366,6 @@ async function mutate(
recovery: { preserveDrafts?: Record; preserveAssign?: boolean; pickingConflict?: boolean } = {},
) {
mutating.value = true
- mutationError.value = null
try {
await action()
} catch (error) {
@@ -349,12 +375,11 @@ async function mutate(
const pickingMessage = recovery.pickingConflict && details.message.includes('拣货')
? '该订单在拣货中不许删除'
: null
- mutationError.value = { ...details, message: pickingMessage || '方案已被其他人修改,已刷新最新版本并保留本次输入,请重新确认后提交' }
+ const message = pickingMessage || '方案已被其他人修改,已刷新最新版本,请重新确认后提交'
if (recovery.preserveAssign) assignOpen.value = true
if (pickingMessage) ElMessage.error(pickingMessage)
- else ElMessage.warning(mutationError.value.message)
+ else ElMessage.warning(message)
} else {
- mutationError.value = details
ElMessage.error(details.message)
}
} finally {
@@ -368,26 +393,24 @@ onMounted(() => { void load(); void loadCustomers() })
-
+
+
+
+
+
+ - 候选货物
- {{ filteredCandidates.length }} 条
+ - 空柜
- {{ filteredContainers.length }} 个
+ - 已装
- {{ totalPackages }} 箱
+ - 总重量
- {{ formatNumber(totalWeight, 1) }} kg
+ - 总体积
- {{ formatNumber(totalVolume) }} m³
+
+
@@ -396,18 +419,6 @@ onMounted(() => { void load(); void loadCustomers() })
-
-
-
-
-
- 候选货物{{ filteredCandidates.length }}
- 可见空柜{{ filteredContainers.length }}
- 当前已装箱数{{ totalPackages }}
- 当前总体积{{ formatNumber(totalVolume) }} m³
- 当前总重量{{ formatNumber(totalWeight, 1) }} kg
-
-
@@ -430,7 +441,7 @@ onMounted(() => { void load(); void loadCustomers() })
@click="openAssign(row)"
>加入
- {{ row.orderNo || '—' }}{{ row.inboundCode || '—' }}
+ {{ row.inboundCode || '—' }}
{{ formatNumber(Number(row.unitVolumeCbm || 0)) }} m³
{{ formatNumber(Number(row.unitWeightKg || 0), 1) }} kg
@@ -464,6 +475,7 @@ onMounted(() => { void load(); void loadCustomers() })
智能推荐
+ 全部移除
推送预装
@@ -488,9 +500,9 @@ onMounted(() => { void load(); void loadCustomers() })
保存移除
- {{ row.orderNo || '—' }}{{ row.inboundCode || '—' }}
+ {{ row.inboundCode || '—' }}
{{ row.productNameZh || '未命名货物' }}{{ row.skuCode || '无 SKU' }}
-
+
{{ formatNumber(Number(row.volumeCbm || 0)) }} m³
{{ formatNumber(Number(row.grossWeightKg || 0), 1) }} kg
@@ -501,7 +513,7 @@ onMounted(() => { void load(); void loadCustomers() })
{{ selectedCandidate.goodsName || '未命名货物' }}
-
{{ selectedCandidate.orderNo || '—' }} · 可用 {{ selectedCandidate.availablePackageCount }} 箱
+
{{ selectedCandidate.inboundCode || '入仓码暂缺' }} · 可用 {{ selectedCandidate.availablePackageCount }} 箱
@@ -513,30 +525,33 @@ onMounted(() => { void load(); void loadCustomers() })
diff --git a/src/modules/container-loading/pages/SmartLoadingWorkbenchView.test.ts b/src/modules/container-loading/pages/SmartLoadingWorkbenchView.test.ts
index 9203a031..4db61d67 100644
--- a/src/modules/container-loading/pages/SmartLoadingWorkbenchView.test.ts
+++ b/src/modules/container-loading/pages/SmartLoadingWorkbenchView.test.ts
@@ -43,12 +43,14 @@ describe('SmartLoadingWorkbenchView', () => {
expect(getContainer).toHaveBeenCalledWith(container.id)
expect(getSmartLoadingPlanByBooking).toHaveBeenCalledWith(container.id)
expect(listSmartLoadingCandidates).toHaveBeenCalledWith(container.id, '8')
- expect(wrapper.text()).toContain('LP-99')
- expect(wrapper.text()).toContain('ORD-1')
- expect(wrapper.text()).toContain('按 110% 上限')
+ expect(wrapper.text()).toContain('MSCU-1 装柜方案')
+ expect(wrapper.text()).not.toContain('LP-99')
+ expect(wrapper.text()).toContain('IN-1')
+ expect(wrapper.text()).not.toContain('ORD-1')
+ expect(wrapper.text()).toContain('110% 容量上限')
})
- it('keeps picking containers editable while hiding the push action', async () => {
+ it('keeps picking containers out of intelligent loading and links to the preload list', async () => {
vi.mocked(getContainer).mockResolvedValue({ ...container, planStatus: 'LOADING' })
vi.mocked(getSmartLoadingPlanByBooking).mockResolvedValue({ id: '99', bookingId: container.id, planNo: 'LP-99', status: 'LOADING', containerNo: 'MSCU-1', voyageNo: null, version: 2, items: [] })
const router = createRouter({ history: createMemoryHistory(), routes: [{ path: '/container-loading/:containerId/smart-loading', component: SmartLoadingWorkbenchView }] })
@@ -56,12 +58,12 @@ describe('SmartLoadingWorkbenchView', () => {
const wrapper = mount(SmartLoadingWorkbenchView, { global: { plugins: [ElementPlus, router] } })
await flushPromises()
- expect(getSmartLoadingPlanByBooking).toHaveBeenCalledWith(container.id)
- expect(listSmartLoadingCandidates).toHaveBeenCalledWith(container.id, container.warehouseId)
- expect(wrapper.text()).toContain('拣货中')
- expect(wrapper.text()).toContain('智能推荐')
- expect(wrapper.text()).toContain('ORD-1')
- expect(wrapper.findAll('button').some((button) => button.text().includes('推送预装'))).toBe(false)
+ expect(getSmartLoadingPlanByBooking).not.toHaveBeenCalled()
+ expect(listSmartLoadingCandidates).not.toHaveBeenCalled()
+ expect(wrapper.text()).toContain('该柜号已进入拣货流程')
+ expect(wrapper.text()).toContain('查看预装清单')
+ expect(wrapper.text()).not.toContain('智能推荐')
+ expect(wrapper.text()).not.toContain('ORD-1')
})
it('refreshes the latest plan after A0409', async () => {
@@ -80,7 +82,6 @@ describe('SmartLoadingWorkbenchView', () => {
await wrapper.findAll('button').find((button) => button.text().includes('智能推荐'))!.trigger('click')
await flushPromises()
expect(getSmartLoadingPlanByBooking).toHaveBeenCalledTimes(2)
- expect(wrapper.text()).toContain('版本 3')
expect(wrapper.text()).toContain('已刷新最新版本')
expect(wrapper.text()).toContain('request-1')
})
@@ -92,6 +93,8 @@ describe('SmartLoadingWorkbenchView', () => {
expect(source).toContain("canPush && plan?.status === 'EDITING'")
expect(source).not.toContain("canPush && plan?.status === 'EDITING' && container?.containerNo")
expect(source).not.toContain('link type="primary" :disabled="!routeMatches(row)')
+ expect(source).not.toContain("label: '目的仓'")
+ expect(source).not.toContain('plan.planNo')
expect(source.match(/]*\bstripe\b/g)).toHaveLength(2)
})
})
diff --git a/src/modules/container-loading/pages/SmartLoadingWorkbenchView.vue b/src/modules/container-loading/pages/SmartLoadingWorkbenchView.vue
index e1caa711..36a25210 100644
--- a/src/modules/container-loading/pages/SmartLoadingWorkbenchView.vue
+++ b/src/modules/container-loading/pages/SmartLoadingWorkbenchView.vue
@@ -53,7 +53,7 @@ const displayedWeightPercent = computed(() => percentage(weightPercent.value))
const itemColumns: DataTableColumn[] = [
{ key: 'actions', label: '操作', width: 180, fixed: 'left', slotName: 'actions' },
{ key: 'sequence', prop: 'loadSequence', label: '顺序', width: 75 },
- { key: 'order', label: '订单/入库单', minWidth: 190, slotName: 'order' },
+ { key: 'order', label: '入仓码', minWidth: 190, slotName: 'order' },
{ key: 'customerName', prop: 'customerName', label: '客户', minWidth: 150 },
{ key: 'goods', label: '货物', minWidth: 190, slotName: 'goods' },
{ key: 'packageCount', label: '分配箱数', width: 150, slotName: 'packageCount' },
@@ -62,7 +62,7 @@ const itemColumns: DataTableColumn[] = [
]
const candidateColumns: DataTableColumn[] = [
{ key: 'actions', label: '操作', width: 110, fixed: 'left', slotName: 'actions' },
- { key: 'order', label: '订单/入库单', minWidth: 190, slotName: 'order' },
+ { key: 'order', label: '入仓码', minWidth: 190, slotName: 'order' },
{ key: 'customerName', prop: 'customerName', label: '客户', minWidth: 150 },
{ key: 'goodsName', prop: 'goodsName', label: '货物', minWidth: 180 },
{ key: 'availablePackageCount', prop: 'availablePackageCount', label: '可用箱数', width: 110 },
@@ -157,7 +157,7 @@ async function adjust(source: object) {
async function remove(source: object) {
const item = itemRow(source)
if (!plan.value) return
- await ElMessageBox.confirm(`确认从计划移除“${item.productNameZh || item.orderNo || '该货物'}”吗?`, '移除装柜明细', { type: 'warning', confirmButtonText: '移除', cancelButtonText: '取消' }).catch(() => false).then(async (confirmed) => {
+ await ElMessageBox.confirm(`确认从计划移除“${item.productNameZh || item.inboundCode || '该货物'}”吗?`, '移除装柜明细', { type: 'warning', confirmButtonText: '移除', cancelButtonText: '取消' }).catch(() => false).then(async (confirmed) => {
if (!confirmed || !plan.value) return
mutating.value = true
mutationError.value = null
@@ -232,7 +232,7 @@ onMounted(load)
{{ displayContainerNo(container) }} 装柜方案
智能建议必须经人工核对。
保存箱数移除
- {{ row.orderNo || '—' }}{{ row.inboundCode || '—' }}
+ {{ row.inboundCode || '—' }}
{{ row.productNameZh || '未命名货物' }}{{ row.skuCode || '无 SKU' }}
{{ formatNumber(Number(row.volumeCbm || 0)) }} m³{{ formatNumber(Number(row.grossWeightKg || 0),1) }} kg
@@ -240,13 +240,13 @@ onMounted(load)
候选货物
系统基于装柜仓库、物流渠道、可用箱数及 110% 容量上限校验。
分配
- {{ row.orderNo || '—' }}{{ row.inboundCode || '—' }}
+ {{ row.inboundCode || '—' }}
{{ formatNumber(Number(row.unitVolumeCbm || 0)) }} m³{{ formatNumber(Number(row.unitWeightKg || 0),1) }} kg
- {{ selectedCandidate.goodsName || '未命名货物' }}
{{ selectedCandidate.orderNo || '—' }} · 可用 {{ selectedCandidate.availablePackageCount }} 箱
+ {{ selectedCandidate.goodsName || '未命名货物' }}
{{ selectedCandidate.inboundCode || '入仓码暂缺' }} · 可用 {{ selectedCandidate.availablePackageCount }} 箱
@@ -262,7 +262,7 @@ onMounted(load)
.workbench h2 + p,.workbench small { display: block; margin-top: 4px; color: var(--cc-muted); }
.header-actions,.row-actions { flex-wrap: wrap; gap: 8px; }
.header-actions :deep(.el-button + .el-button),.row-actions :deep(.el-button + .el-button) { margin-left: 0; }
-.summary-band { display: grid; grid-template-columns: repeat(4,minmax(0,1fr)); gap: 1px; border: 1px solid var(--cc-border); background: var(--cc-border); }
+.summary-band { display: grid; grid-template-columns: repeat(2,minmax(0,1fr)); gap: 1px; border: 1px solid var(--cc-border); background: var(--cc-border); }
.summary-band>div { display: grid; gap: 5px; padding: 14px; background: #fff; }
.summary-band span { color: var(--cc-muted); font-size: 12px; }
.capacity-grid { display: grid; grid-template-columns: repeat(2,minmax(0,1fr)); gap: 16px; padding: 16px; border: 1px solid var(--cc-border); border-radius: 8px; background: #fff; }
diff --git a/src/modules/inbounds/components/InboundTaskList.vue b/src/modules/inbounds/components/InboundTaskList.vue
index c97145ad..6bb5377d 100644
--- a/src/modules/inbounds/components/InboundTaskList.vue
+++ b/src/modules/inbounds/components/InboundTaskList.vue
@@ -23,7 +23,6 @@ import WeightOcrPanel from '../weight/components/WeightOcrPanel.vue'
type FilterModel = QueryModel & {
customerId: string
inboundCode: string
- orderNo: string
warehouseId: string
expectedArrivalRange: string[]
}
@@ -36,7 +35,7 @@ const pageSize = ref(20)
const loading = ref(false)
const loadError = ref(null)
const result = ref({ records: [] as InboundOrderSummary[], total: 0 })
-const filters = ref({ customerId: '', inboundCode: '', orderNo: '', warehouseId: '', expectedArrivalRange: [] })
+const filters = ref({ customerId: '', inboundCode: '', warehouseId: '', expectedArrivalRange: [] })
const appliedFilters = ref({ ...filters.value, expectedArrivalRange: [] })
const customers = ref([])
const customerLoadError = ref(null)
@@ -72,7 +71,6 @@ const queryFields = computed(() => [
},
{ key: 'warehouseId', type: 'select', label: '定位仓库', width: 220, placeholder: '全部仓库', options: warehouseOptions.value, props: { filterable: true } },
{ key: 'inboundCode', type: 'input', label: '入仓码', width: 220, placeholder: '请输入入仓码' },
- { key: 'orderNo', type: 'input', label: '订单号', width: 220, placeholder: '请输入订单号' },
{ key: 'expectedArrivalRange', type: 'daterange', label: '预计到达时间', width: 320, placeholder: '请选择日期范围' },
])
@@ -142,7 +140,6 @@ async function loadTasks() {
size: pageSize.value,
warehouseId: applied.warehouseId || undefined,
inboundCode: applied.inboundCode.trim() || undefined,
- orderNo: applied.orderNo.trim() || undefined,
expectedArrivalFrom: dateParam(applied.expectedArrivalRange[0]),
expectedArrivalTo: dateParam(applied.expectedArrivalRange[1], true),
}))
@@ -163,7 +160,7 @@ function applyFilters() {
}
function resetFilters() {
- filters.value = { customerId: '', inboundCode: '', orderNo: '', warehouseId: '', expectedArrivalRange: [] }
+ filters.value = { customerId: '', inboundCode: '', warehouseId: '', expectedArrivalRange: [] }
appliedFilters.value = { ...filters.value, expectedArrivalRange: [] }
if (page.value === 1) void loadTasks()
else page.value = 1
@@ -260,7 +257,7 @@ onBeforeUnmount(() => { disposed = true; requestSerial += 1; optionsRequestSeria
无操作权限
- {{ text((row as InboundOrderSummary).inboundCode) }}订单 {{ text((row as InboundOrderSummary).orderNo) }}
+ {{ text((row as InboundOrderSummary).inboundCode) }}
{{ inboundStatusLabel((row as InboundOrderSummary).processStatus, inboundProcessStatusLabels) }}
{{ inboundStatusLabel((row as InboundOrderSummary).measureReviewStatus, inboundReviewStatusLabels) }}
{{ formatDate((row as InboundOrderSummary).expectedArrivalAt) }}
diff --git a/src/modules/inbounds/components/InboundWorkflowWorkspace.test.ts b/src/modules/inbounds/components/InboundWorkflowWorkspace.test.ts
index b33a3906..db4cf041 100644
--- a/src/modules/inbounds/components/InboundWorkflowWorkspace.test.ts
+++ b/src/modules/inbounds/components/InboundWorkflowWorkspace.test.ts
@@ -23,9 +23,9 @@ describe('InboundWorkflowWorkspace', () => {
})
it('opens measurement editing and review in prototype-sized centered dialogs', () => {
- expect(source).toContain('title="编辑入库测量数据"')
+ expect(source).toContain(':title="`测量 · ${title}`"')
expect(source).toContain('width="min(1240px, calc(100vw - 32px))"')
- expect(source).toContain('title="审核入库测量数据"')
+ expect(source).toContain(':title="`测量审核 · ${title}`"')
expect(source).toContain('width="min(1240px, calc(100vw - 32px))"')
expect(source).toContain('height: 92vh')
expect(source).toContain('max-height: 92vh')
diff --git a/src/modules/inbounds/components/InboundWorkflowWorkspace.vue b/src/modules/inbounds/components/InboundWorkflowWorkspace.vue
index e68784eb..0ebf879f 100644
--- a/src/modules/inbounds/components/InboundWorkflowWorkspace.vue
+++ b/src/modules/inbounds/components/InboundWorkflowWorkspace.vue
@@ -194,7 +194,7 @@ onBeforeUnmount(() => {
{
) { return in
-
入库码:{{ summary.inboundCode || `入库单 ${summary.id}` }}
-
订单 {{ value(summary.orderNo) }} · {{ value(summary.customerName) }}
+
入仓码:{{ summary.inboundCode || '暂缺' }}
+
{{ value(summary.customerName) }}
{{ processLabel(summary.processStatus) }}
@@ -39,7 +39,6 @@ function label(value: string | null, labels: Record) { return in
基本信息
- - 头程订单号
- {{ value(summary.orderNo) }}
- 订单状态
- {{ label(summary.orderStatusSnapshot, inboundOrderStatusLabels) }}
- 客户
- {{ value(summary.customerName) }}
- 公司
- {{ value(summary.companyName) }}
diff --git a/src/modules/inbounds/measurement/InboundMeasurementPanel.test.ts b/src/modules/inbounds/measurement/InboundMeasurementPanel.test.ts
index abbbc8d5..89543dfc 100644
--- a/src/modules/inbounds/measurement/InboundMeasurementPanel.test.ts
+++ b/src/modules/inbounds/measurement/InboundMeasurementPanel.test.ts
@@ -149,13 +149,13 @@ describe('InboundMeasurementPanel', () => {
const wrapper = await mountPanel()
expect(getInboundMeasurement).toHaveBeenCalledWith('10001', '7001')
- expect((wrapper.find('input[readonly]').element as HTMLInputElement).value).toBe('RK202608040001')
expect(wrapper.text()).toContain('RK202608040001')
- expect(wrapper.text()).toContain('周长(cm)')
- expect(wrapper.find('.measurement-table').text()).toContain('190')
expect(wrapper.find('.measurement-table').text()).toContain('0.6')
+ expect(wrapper.find('.measurement-table').text()).not.toContain('周长')
await wrapper.find('.el-table__expand-icon').trigger('click')
await flushPromises()
+ expect(wrapper.text()).toContain('箱规周长')
+ expect(wrapper.text()).toContain('190 cm')
expect(wrapper.text()).toContain('MJ20210327')
expect(wrapper.text()).toContain('2026-08-04 10:30:00+08:00')
expect(wrapper.find('button[aria-label="预览测量图片"]').exists()).toBe(true)
@@ -189,27 +189,29 @@ describe('InboundMeasurementPanel', () => {
const wrapper = await mountPanel()
- expect(wrapper.findAll('input[readonly]').some((input) => (input.element as HTMLInputElement).value === '未知来源')).toBe(true)
+ expect(wrapper.text()).toContain('未知来源')
expect(wrapper.text()).not.toContain('LEGACY_DEVICE')
})
- it('follows the prototype grouping, labels, and editable field order', async () => {
+ it('keeps the first view focused on key totals and moves secondary fields behind disclosure', async () => {
const wrapper = await mountPanel()
const text = wrapper.text()
- expect(text).toContain('原单数据与测量汇总')
- expect(text).toContain('扫描箱测量数据明细')
- expect(text).toContain('订单总箱数')
- expect(text).toContain('确认箱数合计')
- expect(text).toContain('货物总重量')
- expect(text).toContain('实测总体积')
- expect(text).toContain('实测总材积重')
+ expect(text).toContain('实测箱数')
+ expect(text).toContain('货物重量')
+ expect(text).toContain('总体积')
+ expect(text).toContain('材积重')
+ expect(text).toContain('申报信息')
+ expect(text).toContain('箱规明细')
expect(text).not.toContain('租户')
+ expect(text).not.toContain('数据版本')
expect(wrapper.find('.measurement-table').exists()).toBe(true)
expect(wrapper.find('.measurement-item').exists()).toBe(false)
- expect(wrapper.find('.measurement-table').text()).toContain('周长(cm)')
+ expect(wrapper.find('.measurement-table').text()).not.toContain('周长')
const source = await import('./InboundMeasurementPanel.vue?raw').then((module) => module.default)
+ expect(source).toContain('')
+ expect(source).toContain('grid-template-columns: repeat(4, minmax(0, 1fr))')
expect(source).toContain('.measurement-form-grid, .measurement-data-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));')
expect(source).toContain('.measurement-table { width: 100%; font-size: 12px; }')
expect(source).toContain('.measurement-data-grid :deep(.el-input__wrapper)')
@@ -224,7 +226,7 @@ describe('InboundMeasurementPanel', () => {
wrapper.vm.updateActualGrossWeight(125.75)
await flushPromises()
- expect(wrapper.findAll('input[readonly]').some((input) => (input.element as HTMLInputElement).value === '125.75')).toBe(true)
+ expect(wrapper.find('.measurement-metrics').text()).toContain('125.75')
expect((countInput.element as HTMLInputElement).value).toBe('9')
})
@@ -232,8 +234,8 @@ describe('InboundMeasurementPanel', () => {
const wrapper = await mountPanel()
expect(wrapper.classes()).toContain('surface-panel')
- expect(wrapper.find('.measurement-panel__heading').exists()).toBe(true)
- expect(wrapper.findAll('input[readonly]').some((input) => (input.element as HTMLInputElement).value === '测量中')).toBe(true)
+ expect(wrapper.find('.measurement-summary-header').exists()).toBe(true)
+ expect(wrapper.find('.measurement-summary-status').text()).toContain('测量中')
})
it('saves only the changed confirmed package count with the current measurement version', async () => {
@@ -343,8 +345,9 @@ describe('InboundMeasurementPanel', () => {
await flushPromises()
expect(getInboundMeasurement).toHaveBeenLastCalledWith('10002', '7002')
- expect(wrapper.findAll('input[readonly]').some((input) => (input.element as HTMLInputElement).value === 'RK202608040002')).toBe(true)
- expect(wrapper.findAll('input[readonly]').some((input) => (input.element as HTMLInputElement).value === '测试企业')).toBe(false)
+ expect(wrapper.find('.measurement-summary-header').text()).toContain('RK202608040002')
+ expect(wrapper.find('.measurement-summary-header').text()).toContain('第二企业')
+ expect(wrapper.find('.measurement-summary-header').text()).not.toContain('测试企业')
})
it('renders a permission-specific read-only state without requesting data', async () => {
diff --git a/src/modules/inbounds/measurement/InboundMeasurementPanel.vue b/src/modules/inbounds/measurement/InboundMeasurementPanel.vue
index 8b4eecb6..5a3c56b1 100644
--- a/src/modules/inbounds/measurement/InboundMeasurementPanel.vue
+++ b/src/modules/inbounds/measurement/InboundMeasurementPanel.vue
@@ -516,32 +516,45 @@ defineExpose({ saveDraft, submitForReview, updateActualGrossWeight, mayMaintain,