This commit is contained in:
2026-08-12 14:57:02 +08:00
parent 975e0057e3
commit 1ee5a2dec7
10 changed files with 85 additions and 74 deletions
@@ -100,6 +100,7 @@ function measurement(overrides: Partial<InboundMeasurementDetail> = {}): Inbound
async function mountPanel(permissions = [
'platform:firstleg:inbound:measure:view',
'platform:firstleg:inbound:measure:edit',
'platform:firstleg:inbound:measure:manual-entry',
'platform:firstleg:inbound:measure:submit',
]) {
const pinia = createPinia()
@@ -170,6 +171,16 @@ describe('InboundMeasurementPanel', () => {
expect(document.body.textContent).toContain('保存箱规')
})
it('does not expose manual carton entry without its dedicated permission', async () => {
const wrapper = await mountPanel([
'platform:firstleg:inbound:measure:view',
'platform:firstleg:inbound:measure:edit',
'platform:firstleg:inbound:measure:submit',
])
expect(wrapper.text()).not.toContain('手动录入箱规')
})
it('does not expose unknown measurement source codes', async () => {
vi.mocked(getInboundMeasurement).mockResolvedValueOnce(measurement({ sourceType: 'LEGACY_DEVICE' }))
@@ -97,6 +97,7 @@ const manualForm = reactive<ManualCartonFormModel>({
const canView = computed(() => access.can('platform:firstleg:inbound:measure:view'))
const canEdit = computed(() => access.can('platform:firstleg:inbound:measure:edit'))
const canManualEntry = computed(() => access.can('platform:firstleg:inbound:measure:manual-entry'))
const canSubmit = computed(() => access.can('platform:firstleg:inbound:measure:submit'))
const customerId = computed(() => props.customerId || props.tenantId || '')
const hasContext = computed(() => Boolean(customerId.value && props.inboundId))
@@ -104,7 +105,7 @@ const countEditableProcess = computed(() => ['WAIT_MEASURE', 'MEASURING', 'MEASU
const submitEditableProcess = computed(() => ['WAIT_MEASURE', 'MEASURING', 'MEASURE_REJECTED'].includes(detail.value?.processStatus || ''))
const mayMaintain = computed(() => canEdit.value && countEditableProcess.value && !loading.value && !submitting.value)
const manualEntryEditableProcess = computed(() => ['WAIT_MEASURE', 'MEASURING', 'MEASURE_REJECTED'].includes(detail.value?.processStatus || ''))
const mayCreateManualEntry = computed(() => canEdit.value && manualEntryEditableProcess.value && !loading.value && !saving.value && !submitting.value && !isDirty.value)
const mayCreateManualEntry = computed(() => canManualEntry.value && manualEntryEditableProcess.value && !loading.value && !saving.value && !submitting.value && !isDirty.value)
const confirmedPackageCount = computed(() => form.items.reduce((sum, item) => sum + (Number.isFinite(item.packageCount) ? item.packageCount : 0), 0))
const expectedPackageCount = computed(() => detail.value?.originalPackageCount ?? null)
const packageCountDifference = computed(() => expectedPackageCount.value == null ? null : confirmedPackageCount.value - expectedPackageCount.value)
@@ -556,7 +557,7 @@ onBeforeUnmount(releaseImagePreview)
<section class="measurement-section measurement-items-section">
<div class="measurement-section__heading">
<div><h3>扫描箱测量数据明细</h3><p>每条记录对应一个实际扫描箱;人工只确认该条记录代表的箱数,设备实测值不可在此修改。</p></div>
<el-button v-if="canEdit" type="primary" plain :disabled="!mayCreateManualEntry" @click="openManualEntry"><Plus :size="15" />手动录入箱规</el-button>
<el-button v-if="canManualEntry" type="primary" plain :disabled="!mayCreateManualEntry" @click="openManualEntry"><Plus :size="15" />手动录入箱规</el-button>
</div>
<el-empty v-if="!form.items.length" description="暂无扫描箱测量数据" />
+1 -1
View File
@@ -112,7 +112,7 @@ describe('inbound measurement API', () => {
machineNo: 'MANUAL-ADMIN', measuredAt: '2026-08-12T14:00:00', scannedShipmentId: null,
}, image)).resolves.toEqual(result)
const [path, body, config] = vi.mocked(http.post).mock.calls[0]!
expect(path).toBe('/platform/v1/first-leg/inbounds/7001/measurement/carton-scans')
expect(path).toBe('/platform/v1/first-leg/inbounds/7001/measurement/manual-cartons')
expect(body).toBeInstanceOf(FormData)
expect((body as FormData).get('image')).toBe(image)
expect(config).toEqual({ params: { tenantId: '10001' }, headers: { 'Content-Type': 'multipart/form-data' } })
+1 -1
View File
@@ -78,7 +78,7 @@ export async function createManualCartonScan(
data.append('data', new Blob([JSON.stringify(payload)], { type: 'application/json' }))
data.append('image', image)
const response = await http.post<ApiEnvelope<CartonMeasurementResult>, ApiEnvelope<CartonMeasurementResult>>(
`${measurementPath(inboundId)}/carton-scans`,
`${measurementPath(inboundId)}/manual-cartons`,
data,
{ params: { tenantId: customerId }, headers: { 'Content-Type': 'multipart/form-data' } },
)