fix(inbounds): restore approved measurement workspace
This commit is contained in:
@@ -381,8 +381,8 @@ describe('InboundMeasurementPanel', () => {
|
||||
vi.mocked(getInboundMeasurement).mockResolvedValueOnce(measurement({ measurementId: null, items: [], weightResults: [] }))
|
||||
const wrapper = await mountPanel()
|
||||
expect(wrapper.find('.measurement-summary-header h4').text()).toBe('申报与实测对比')
|
||||
expect(wrapper.find('.measurement-declaration-header').text()).not.toContain('DOC-001')
|
||||
expect(wrapper.find('.measurement-section__heading .measurement-goods-name').exists()).toBe(false)
|
||||
expect(wrapper.find('.measurement-declaration-header').text()).toContain('DOC-001')
|
||||
expect(wrapper.find('.measurement-section__heading .measurement-goods-name input').exists()).toBe(true)
|
||||
expect(wrapper.find('.measurement-section__heading .measurement-section-actions').text()).toContain('手动录入箱规')
|
||||
expect(wrapper.findAll('.el-alert').some(alert => alert.text().includes('请先完成箱规测量'))).toBe(false)
|
||||
expect(wrapper.find('.measurement-panel__footer').text()).toContain('请先完成箱规测量')
|
||||
@@ -396,11 +396,11 @@ describe('InboundMeasurementPanel', () => {
|
||||
expect(comparison.text()).toContain('118.5')
|
||||
expect(comparison.text()).toContain('0.8')
|
||||
expect(comparison.findAll('tbody tr')[0].text()).toContain('10')
|
||||
expect(declaration.text()).not.toContain('原单据号码')
|
||||
expect(declaration.text()).not.toContain('DOC-001')
|
||||
expect(declaration.findAll('.measurement-readonly-field')).toHaveLength(0)
|
||||
expect(declaration.text()).toContain('原单据号码')
|
||||
expect(declaration.text()).toContain('DOC-001')
|
||||
expect(declaration.findAll('.measurement-readonly-field')).toHaveLength(1)
|
||||
expect(declaration.findAll('input')).toHaveLength(0)
|
||||
expect(wrapper.find('.measurement-items-section .measurement-goods-name').exists()).toBe(false)
|
||||
expect(wrapper.find('.measurement-items-section .measurement-goods-name input').exists()).toBe(true)
|
||||
expect(declaration.find('[aria-label="客户申报箱规明细"]').text()).toContain('蓝牙音箱')
|
||||
expect(declaration.find('[aria-label="客户申报箱规明细"]').text()).toContain('50 × 40 × 30')
|
||||
})
|
||||
@@ -418,14 +418,18 @@ describe('InboundMeasurementPanel', () => {
|
||||
|
||||
expect(declaration.find('input').exists()).toBe(false)
|
||||
expect(declaration.text()).toContain('蓝牙音箱')
|
||||
expect(declaration.findAll('.measurement-readonly-field')).toHaveLength(0)
|
||||
expect(wrapper.find('.measurement-items-section .measurement-goods-name').exists()).toBe(false)
|
||||
expect(declaration.findAll('.measurement-readonly-field')).toHaveLength(1)
|
||||
const actualGoods = wrapper.get('.measurement-items-section .measurement-goods-name')
|
||||
expect(actualGoods.text()).toContain('蓝牙音箱')
|
||||
expect(actualGoods.find('input').exists()).toBe(false)
|
||||
})
|
||||
|
||||
it('preserves the hidden actual goods name without overriding declaration facts', async () => {
|
||||
it('saves the edited actual goods name without overriding declaration facts', async () => {
|
||||
const wrapper = await mountPanel()
|
||||
expect(wrapper.text()).not.toContain('实际品名')
|
||||
await wrapper.find('input[aria-label="仓库修改外箱长"]').setValue('55')
|
||||
expect(wrapper.get<HTMLInputElement>('input[aria-label="实际品名"]').element.value).toBe('蓝牙音箱')
|
||||
await wrapper.get('input[aria-label="实际品名"]').setValue(' 实测蓝牙音箱 ')
|
||||
expect(wrapper.get('.measurement-declaration').text()).toContain('蓝牙音箱')
|
||||
expect(wrapper.get('.measurement-declaration').text()).not.toContain('实测蓝牙音箱')
|
||||
const save = wrapper.findAll('button').find((button) => button.text().includes('保存测量数据'))
|
||||
await save?.trigger('click')
|
||||
await flushPromises()
|
||||
@@ -433,7 +437,7 @@ describe('InboundMeasurementPanel', () => {
|
||||
expect(saveInboundMeasurementDraft).toHaveBeenCalledWith('10001', '7001', expect.objectContaining({
|
||||
measurementId: '9001',
|
||||
version: 2,
|
||||
actualGoodsName: '蓝牙音箱',
|
||||
actualGoodsName: '实测蓝牙音箱',
|
||||
items: expect.any(Array),
|
||||
}))
|
||||
const payload = vi.mocked(saveInboundMeasurementDraft).mock.calls[0]?.[2]
|
||||
@@ -630,7 +634,7 @@ describe('InboundMeasurementPanel', () => {
|
||||
const wrapper = await mountPanel()
|
||||
expect(wrapper.find('.measurement-declaration input').exists()).toBe(false)
|
||||
expect(wrapper.find('.measurement-items-section .measurement-expected-pallets input').exists()).toBe(true)
|
||||
expect(wrapper.find('.measurement-items-section .measurement-goods-name').exists()).toBe(false)
|
||||
expect(wrapper.find('.measurement-items-section .measurement-goods-name input').exists()).toBe(true)
|
||||
})
|
||||
|
||||
it('requires at least one confirmed weight image before submitting for review', async () => {
|
||||
|
||||
@@ -736,7 +736,7 @@ defineExpose({ saveDraft, submitForReview, updateWeightEvidence, submissionBlock
|
||||
<p v-for="warning in measurementDeviationWarnings" :key="warning.key">{{ warning.text }}</p>
|
||||
</el-alert>
|
||||
|
||||
<div class="workbench-evidence"><table class="measurement-comparison" aria-label="客户申报与平台实测对比">
|
||||
<table class="measurement-comparison" aria-label="客户申报与平台实测对比">
|
||||
<thead><tr><th scope="col">指标</th><th scope="col">客户申报</th><th scope="col">平台实测</th><th scope="col">差异(实测 − 申报)</th></tr></thead>
|
||||
<tbody>
|
||||
<tr v-for="metric in comparisonMetrics" :key="metric.label">
|
||||
@@ -748,7 +748,7 @@ defineExpose({ saveDraft, submitForReview, updateWeightEvidence, submissionBlock
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></div>
|
||||
</table>
|
||||
<div class="measurement-extra-facts">
|
||||
<span>货物净重 <strong>{{ formatNumber(detail.actualNetWeightKg) }}</strong> kg</span>
|
||||
<span>计费材积重 <strong>{{ formatNumber(detail.volumeWeightKg) }}</strong> kg</span>
|
||||
@@ -759,6 +759,7 @@ defineExpose({ saveDraft, submitForReview, updateWeightEvidence, submissionBlock
|
||||
<section class="measurement-declaration" aria-labelledby="measurement-declaration-title">
|
||||
<header class="measurement-declaration-header">
|
||||
<h4 id="measurement-declaration-title">客户申报明细</h4>
|
||||
<div class="measurement-readonly-field measurement-document-number"><span>原单据号码</span><strong>{{ detail.originalDocumentNo || '—' }}</strong></div>
|
||||
</header>
|
||||
<el-table
|
||||
v-if="detail.latestDeclaration?.items.length"
|
||||
@@ -782,7 +783,9 @@ defineExpose({ saveDraft, submitForReview, updateWeightEvidence, submissionBlock
|
||||
<div class="measurement-section__heading">
|
||||
<div><h3>平台实测箱规</h3></div>
|
||||
|
||||
<div v-if="isDropship" class="measurement-data-grid measurement-platform-fields">
|
||||
<div class="measurement-data-grid measurement-platform-fields">
|
||||
<label v-if="mayMaintain" class="measurement-goods-name"><span>实际品名</span><el-input v-model="form.actualGoodsName" aria-label="实际品名" placeholder="请输入实际品名" maxlength="255" /></label>
|
||||
<div v-else class="measurement-readonly-field measurement-goods-name"><span>实际品名</span><strong>{{ detail.actualGoodsName || '—' }}</strong></div>
|
||||
<label v-if="isDropship && mayMaintain" class="measurement-expected-pallets"><span>预计托数</span><el-input-number v-model="form.expectedPalletCount" placeholder="请输入预计托数" :min="1" :max="1000" :step="1" step-strictly controls-position="right" /></label>
|
||||
<div v-else-if="isDropship" class="measurement-readonly-field measurement-expected-pallets"><span>预计托数</span><strong>{{ detail.expectedPalletCount ?? '—' }}</strong></div>
|
||||
</div>
|
||||
@@ -927,9 +930,9 @@ defineExpose({ saveDraft, submitForReview, updateWeightEvidence, submissionBlock
|
||||
<style scoped>
|
||||
.measurement-comparison { width: 100%; border-collapse: collapse; table-layout: fixed; background: var(--admin-surface, #fff); font-size: var(--admin-font-body, 13px); }
|
||||
.measurement-comparison th, .measurement-comparison td { padding: var(--admin-space-3, 8px) var(--admin-space-5, 12px); border: 1px solid var(--workbench-border); text-align: left; overflow-wrap: anywhere; font-variant-numeric: tabular-nums; }
|
||||
.measurement-comparison thead th { background: var(--cc-list-table-header-bg); color: var(--cc-list-table-header-text); }
|
||||
.measurement-comparison thead th:nth-child(2) { background: #f7f9ff; color: #465fc4; }
|
||||
.measurement-comparison thead th:nth-child(3) { background: var(--admin-surface, #fff); color: #18795d; }
|
||||
.measurement-comparison thead th { background: var(--admin-label-bg); color: var(--workbench-text); }
|
||||
.measurement-comparison thead th:nth-child(2) { background: var(--admin-dialog-source-bg); color: #465fc4; }
|
||||
.measurement-comparison thead th:nth-child(3) { background: var(--admin-dialog-summary-bg); color: #18795d; }
|
||||
.measurement-comparison__difference { color: var(--el-color-danger-dark-2); font-weight: 600; }
|
||||
.measurement-extra-facts { display: flex; flex-wrap: wrap; gap: var(--admin-space-3, 8px) var(--admin-space-6, 16px); color: var(--workbench-muted); font-size: var(--admin-font-caption, 12px); }
|
||||
.measurement-extra-facts strong { color: var(--workbench-text); }
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
/* Measurement workspace: keep all sections inside the panel's content bounds. */
|
||||
.inbound-measurement-workspace-dialog.inbound-density .measurement-summary-section { min-width: 0; margin: 0; padding: var(--admin-space-4, 10px) var(--admin-space-5, 12px); border: 1px solid var(--cc-border); border-radius: var(--admin-dialog-section-radius); background: var(--admin-surface, #fff); }
|
||||
/* Approved measurement-only palette; shared dialog styling must preserve these sections and gutters. */
|
||||
.inbound-measurement-workspace-dialog.inbound-density .measurement-summary-section { min-width: 0; margin: 0; padding: var(--admin-space-4, 10px) var(--admin-space-5, 12px); border: 1px solid var(--admin-dialog-summary-border); border-left: 4px solid #20a477; border-radius: var(--admin-dialog-section-radius); background: var(--admin-dialog-summary-bg); }
|
||||
.inbound-measurement-workspace-dialog.inbound-density .measurement-summary-header { flex-wrap: wrap; align-items: center; gap: var(--admin-space-3, 8px) var(--admin-space-6, 16px); }
|
||||
.inbound-measurement-workspace-dialog.inbound-density .measurement-summary-context { flex: 1 1 auto; }
|
||||
.inbound-measurement-workspace-dialog.inbound-density .measurement-summary-context p > span { flex-shrink: 0; }
|
||||
.inbound-measurement-workspace-dialog.inbound-density .measurement-summary-status { flex-wrap: wrap; }
|
||||
.inbound-measurement-workspace-dialog.inbound-density .measurement-items-section { min-width: 0; margin: var(--admin-space-5, 12px) 0 0; padding: var(--admin-space-4, 10px) var(--admin-space-5, 12px); border: 1px solid var(--cc-border); border-radius: var(--admin-dialog-section-radius); background: var(--admin-surface, #fff); }
|
||||
.inbound-measurement-workspace-dialog.inbound-density .measurement-items-section { min-width: 0; margin: var(--admin-space-5, 12px) 0 0; padding: var(--admin-space-4, 10px) var(--admin-space-5, 12px); border: 1px solid var(--admin-dialog-work-border); border-left: 4px solid #c79643; border-radius: var(--admin-dialog-section-radius); background: var(--admin-dialog-work-bg); }
|
||||
|
||||
.inbound-measurement-workspace-dialog.inbound-density .measurement-deviation-alert { background: var(--admin-surface, #fff); }
|
||||
.inbound-measurement-workspace-dialog.inbound-density .measurement-subheading { color: #18795d; font-size: var(--admin-font-section, 14px); }
|
||||
.inbound-measurement-workspace-dialog.inbound-density .measurement-declaration { min-width: 0; margin-top: var(--admin-space-3, 8px); padding: var(--admin-space-4, 10px) var(--admin-space-5, 12px); border: 1px solid var(--admin-dialog-source-border); border-radius: var(--admin-dialog-section-radius); background: var(--admin-dialog-source-bg); }
|
||||
.inbound-measurement-workspace-dialog.inbound-density .measurement-declaration { min-width: 0; margin-top: var(--admin-space-3, 8px); padding: var(--admin-space-4, 10px) var(--admin-space-5, 12px); border: 1px solid var(--admin-dialog-source-border); border-left: 4px solid #647fec; border-radius: var(--admin-dialog-section-radius); background: var(--admin-dialog-source-bg); }
|
||||
.inbound-measurement-workspace-dialog.inbound-density .measurement-declaration-table th.el-table__cell { background: var(--admin-label-bg); color: var(--workbench-muted); }
|
||||
|
||||
@media (min-width: 961px) {
|
||||
.inbound-density.admin-density-dialog .measurement-dialog-weight { padding-bottom: var(--admin-space-4, 10px); }
|
||||
|
||||
@@ -431,7 +431,11 @@ describe('approved Admin density ownership', () => {
|
||||
expect(rules.get(':is(.admin-density, .admin-density-dialog) .density-table--editable .el-form-item.is-error')).toMatchObject({ 'margin-bottom': 'var(--admin-space-5)' })
|
||||
for (const selector of rules.keys()) if (selector.includes('density-dialog-section')) expect(selector.startsWith(':is(.admin-density-dialog, .admin-density-drawer:where(.admin-density-drawer--detail, .admin-density-drawer--editor)) ')).toBe(true)
|
||||
const measured = read('modules/inbounds/measurement/measurementDensity.css')
|
||||
expect(measured).not.toMatch(/border-left(?:-color|-width)?\s*:/)
|
||||
cssRoot(measured).walkRules(rule => {
|
||||
rule.walkDecls(/^border-left/, () => {
|
||||
expect(rule.selector).toMatch(/^\.inbound-measurement-workspace-dialog\.inbound-density \.measurement-(summary-section|declaration|items-section)$/)
|
||||
})
|
||||
})
|
||||
for (const color of ['#f4fbf8', '#f7f9ff', '#fffbf4']) expect(measured).not.toContain(color)
|
||||
for (const file of ['unified-orders/pages/UnifiedOrdersView.vue', 'unified-orders/components/OrderDeclarationEditorDialog.vue', 'unified-orders/components/InboundFeeDetailManager.vue', 'inbounds/measurement/InboundMeasurementPanel.vue', 'inbounds/weight/components/WeightOcrPanel.vue', 'domestic-containers/pages/DomesticContainersView.vue', 'sailing-calendar/pages/SailingCalendarView.vue', 'ocean-bookings/components/OceanBookingPrintDialog.vue', 'ocean-bookings/pages/OceanBookingDetailView.vue', 'trucking/components/TruckAttachmentDialog.vue', 'container-loading/pages/ContainersView.vue', 'container-loading/pages/ContainerDetailView.vue', 'container-loading/components/OceanBookingLinkDialog.vue']) {
|
||||
const source = read('modules/' + file)
|
||||
@@ -1302,13 +1306,20 @@ describe('approved Admin density ownership', () => {
|
||||
sectionStyles.set(rule.selector, declarations)
|
||||
})
|
||||
for (const [section, background] of [
|
||||
['summary-section', 'var(--admin-surface, #fff)'], ['declaration', 'var(--admin-dialog-source-bg)'], ['items-section', 'var(--admin-surface, #fff)'],
|
||||
['summary-section', 'var(--admin-dialog-summary-bg)'], ['declaration', 'var(--admin-dialog-source-bg)'], ['items-section', 'var(--admin-dialog-work-bg)'],
|
||||
]) {
|
||||
expect(sectionStyles.get(`.inbound-measurement-workspace-dialog.inbound-density .measurement-${section}`)).toMatchObject({
|
||||
padding: 'var(--admin-space-4, 10px) var(--admin-space-5, 12px)',
|
||||
background,
|
||||
})
|
||||
}
|
||||
for (const [section, accent] of [['summary-section', '#20a477'], ['declaration', '#647fec'], ['items-section', '#c79643']]) {
|
||||
expect(sectionStyles.get(`.inbound-measurement-workspace-dialog.inbound-density .measurement-${section}`)?.['border-left']).toBe(`4px solid ${accent}`)
|
||||
}
|
||||
expect(differenceStyles.get('.measurement-comparison thead th')).toMatchObject({ background: 'var(--admin-label-bg)' })
|
||||
expect(differenceStyles.get('.measurement-comparison thead th:nth-child(2)')).toMatchObject({ background: 'var(--admin-dialog-source-bg)' })
|
||||
expect(differenceStyles.get('.measurement-comparison thead th:nth-child(3)')).toMatchObject({ background: 'var(--admin-dialog-summary-bg)' })
|
||||
expect(sectionStyles.get('.inbound-measurement-workspace-dialog.inbound-density .measurement-declaration-table th.el-table__cell')).toMatchObject({ background: 'var(--admin-label-bg)', color: 'var(--workbench-muted)' })
|
||||
expect(sectionStyles.get('.inbound-measurement-workspace-dialog.inbound-density .measurement-deviation-alert')?.background).toBe('var(--admin-surface, #fff)')
|
||||
// Shared density must not reset the sections' horizontal gutters.
|
||||
expect(sectionStyles.get('.inbound-density.admin-density-dialog .measurement-section')).toEqual({
|
||||
|
||||
Reference in New Issue
Block a user