This commit is contained in:
wujinliang
2026-08-27 21:48:15 +08:00
parent 550d8add97
commit b47323edf3
53 changed files with 624 additions and 82 deletions
@@ -193,6 +193,12 @@ describe('GlobalSmartLoadingView', () => {
expect(source).toContain('assignForm.packageCount = candidate.availablePackageCount')
})
it('keeps the package count editor inside its table cell without overflow ellipsis', () => {
const source = readFileSync(resolve(process.cwd(), 'src/modules/container-loading/pages/GlobalSmartLoadingView.vue'), 'utf8')
expect(source).toContain('<div class="package-count-editor"><el-input-number')
expect(source).toContain('.plan-pane :deep(.package-count-editor .el-input-number) { width: 100%; min-width: 0; }')
})
it('rounds capacity percentages and hides column settings in embedded tables', async () => {
vi.mocked(getSmartLoadingPlanByBooking).mockResolvedValue({
...plan,
@@ -496,6 +502,10 @@ describe('GlobalSmartLoadingView', () => {
expect(source).toContain('智能推荐')
expect(source).toContain('推送预装')
expect(source).toContain('推送预装的流程说明已由操作确认框承载')
expect(source).toContain('后续还需补集装箱号、确认预装。确认继续?')
expect(source).toContain('预装清单已生成,请继续完成集装箱号和预装确认')
expect(source).not.toContain('关联并放舱真实订舱')
expect(source).not.toContain('订舱放舱')
expect(source).not.toContain("canPush && plan?.status === 'EDITING' && selectedContainer?.containerNo")
})
})
@@ -370,13 +370,13 @@ async function removeAll() {
}
async function pushPreload() {
if (!plan.value) return
const confirmed = await ElMessageBox.confirm('推送后生成预装清单,不会直接开放 PDA。后续还需补集装箱号、关联并放舱真实订舱、确认预装。确认继续?', '推送预装清单', {
const confirmed = await ElMessageBox.confirm('推送后生成预装清单,不会直接开放 PDA。后续还需补集装箱号、确认预装。确认继续?', '推送预装清单', {
type: 'warning', confirmButtonText: '确认推送', cancelButtonText: '取消',
}).catch(() => false)
if (!confirmed || !plan.value) return
await mutate(async () => {
acceptPlan(await pushSmartLoadingPreload(plan.value!.id, plan.value!.version))
ElMessage.success('预装清单已生成,请继续完成集装箱号、订舱放舱和预装确认')
ElMessage.success('预装清单已生成,请继续完成集装箱号和预装确认')
}, '推送预装清单失败')
}
@@ -540,7 +540,7 @@ onMounted(() => { void load(); void loadCustomers() })
</div>
<DataTable :data="displayedPlanItems" :columns="itemColumns" :loading="selectionLoading || mutating" stripe preference-key="global-smart-loading-items" column-settings-mode="hide" empty-text="当前柜次暂无装柜明细">
<template #actions="{ row }"><div class="row-actions"><el-button v-if="canAssign && editable && row.canAdjust" size="small" type="primary" plain :disabled="quantityDrafts[row.id] === row.packageCount" @click="adjust(row)"><Save :size="15" />保存</el-button><el-button v-if="canDelete && editable && row.canRemove" size="small" type="danger" plain @click="remove(row)"><Trash2 :size="15" />移除整票</el-button><small v-if="row.detailCount > 1 && editable">多规格;改箱数请移除后重加</small><small v-if="row.pickedPackageCount > 0">已拣 {{ row.pickedPackageCount }} 箱</small></div></template>
<template #packageCount="{ row }"><el-input-number v-model="quantityDrafts[row.id]" :min="row.minPackageCount" :max="adjustmentMax(row)" :step="1" :disabled="!canAssign || !editable || !row.canAdjust" controls-position="right" /></template>
<template #packageCount="{ row }"><div class="package-count-editor"><el-input-number v-model="quantityDrafts[row.id]" :min="row.minPackageCount" :max="adjustmentMax(row)" :step="1" :disabled="!canAssign || !editable || !row.canAdjust" controls-position="right" /></div></template>
<template #weight="{ row }">{{ formatNumber(Number(row.grossWeightKg || 0), 1) }} kg</template>
<template #volume="{ row }">{{ formatNumber(Number(row.volumeCbm || 0)) }} m³</template>
</DataTable>
@@ -603,7 +603,8 @@ onMounted(() => { void load(); void loadCustomers() })
.readonly-status-card strong { font-size: 16px; }
.readonly-status-card p { max-width: 460px; margin: 0; color: var(--cc-muted); line-height: 1.6; }
.meter-title { justify-content: space-between; margin-bottom: 8px; font-size: 12px; }
.plan-pane :deep(.el-input-number) { width: 120px; }
.package-count-editor { display: flex; min-width: 0; }
.plan-pane :deep(.package-count-editor .el-input-number) { width: 100%; min-width: 0; }
.assign-dialog p { margin: 0 0 10px; }
.assign-dialog :deep(.el-input-number) { width: 100%; }
@media (max-width: 1180px) {
@@ -99,6 +99,10 @@ describe('SmartLoadingWorkbenchView', () => {
expect(source).toContain("canPush && plan?.status === 'EDITING'")
expect(source).not.toContain("canPush && plan?.status === 'EDITING' && container?.containerNo")
expect(source).toContain('推送后生成预装清单,不会直接开放 PDA')
expect(source).toContain('后续还需补集装箱号、确认预装。确认继续?')
expect(source).toContain('预装清单已生成,请继续完成集装箱号和预装确认')
expect(source).not.toContain('关联并放舱真实订舱')
expect(source).not.toContain('订舱放舱')
expect(source).not.toContain('link type="primary" :disabled="!routeMatches(row)')
expect(source).not.toContain("label: '目的仓'")
expect(source).not.toContain('plan.planNo')
@@ -107,4 +111,10 @@ describe('SmartLoadingWorkbenchView', () => {
expect(source).toContain('<span>集装箱号</span>')
expect(source).not.toContain('当前柜号')
})
it('keeps the package count editor inside its table cell without overflow ellipsis', () => {
const source = readFileSync(resolve(process.cwd(), 'src/modules/container-loading/pages/SmartLoadingWorkbenchView.vue'), 'utf8')
expect(source).toContain('<div class="package-count-editor"><el-input-number')
expect(source).toContain('.workbench :deep(.package-count-editor .el-input-number) { width: 100%; min-width: 0; }')
})
})
@@ -201,11 +201,11 @@ async function remove(source: object) {
}
async function pushPreload() {
if (!plan.value) return
const confirmed = await ElMessageBox.confirm('推送后生成预装清单,不会直接开放 PDA。后续还需补集装箱号、关联并放舱真实订舱、确认预装。确认继续?', '推送预装清单', { type: 'warning', confirmButtonText: '确认推送', cancelButtonText: '取消' }).catch(() => false)
const confirmed = await ElMessageBox.confirm('推送后生成预装清单,不会直接开放 PDA。后续还需补集装箱号、确认预装。确认继续?', '推送预装清单', { type: 'warning', confirmButtonText: '确认推送', cancelButtonText: '取消' }).catch(() => false)
if (!confirmed || !plan.value) return
mutating.value = true
mutationError.value = null
try { acceptPlan(await pushSmartLoadingPreload(plan.value.id, plan.value.version)); ElMessage.success('预装清单已生成,请继续完成集装箱号、订舱放舱和预装确认') }
try { acceptPlan(await pushSmartLoadingPreload(plan.value.id, plan.value.version)); ElMessage.success('预装清单已生成,请继续完成集装箱号和预装确认') }
catch (error) { await handleMutationError(error, '推送失败') }
finally { mutating.value = false }
}
@@ -268,7 +268,7 @@ onMounted(load)
<template #actions="{ row }"><div class="row-actions"><el-button v-if="canAssign && editable && row.canAdjust" size="small" type="primary" plain :disabled="quantityDrafts[row.id] === row.packageCount" @click="adjust(row)"><Save :size="15" />保存箱数</el-button><el-button v-if="canDelete && editable && row.canRemove" size="small" type="danger" plain @click="remove(row)"><Trash2 :size="15" />移除整票</el-button><small v-if="row.detailCount > 1 && editable">含 {{ row.detailCount }} 个规格;改箱数请移除后重加</small><small v-if="row.pickedPackageCount > 0">已拣 {{ row.pickedPackageCount }} 箱</small></div></template>
<template #order="{ row }"><strong>{{ row.inboundCode || '—' }}</strong></template>
<template #goods="{ row }"><strong>{{ row.productNameZh || '未命名货物' }}</strong><small>{{ row.skuCode || '无 SKU' }}</small></template>
<template #packageCount="{ row }"><el-input-number v-model="quantityDrafts[row.id]" :min="row.minPackageCount" :step="1" :disabled="!canAssign || !editable || !row.canAdjust" controls-position="right" /></template>
<template #packageCount="{ row }"><div class="package-count-editor"><el-input-number v-model="quantityDrafts[row.id]" :min="row.minPackageCount" :step="1" :disabled="!canAssign || !editable || !row.canAdjust" controls-position="right" /></div></template>
<template #volume="{ row }">{{ formatNumber(Number(row.volumeCbm || 0)) }} m³</template><template #weight="{ row }">{{ formatNumber(Number(row.grossWeightKg || 0),1) }} kg</template>
</DataTable>
<DataTable :data="candidates" :columns="candidateColumns" :loading="loading || mutating" stripe preference-key="smart-loading-candidates" column-settings-mode="hide" empty-text="当前仓库暂无可排柜货物">
@@ -306,7 +306,8 @@ onMounted(load)
.readonly-status-card p { margin: 0; color: var(--cc-muted); }
.meter-title { justify-content: space-between; gap: 12px; margin-bottom: 10px; font-size: 13px; }
.row-actions { min-width: 150px; }
.workbench :deep(.el-input-number) { width: 130px; }
.package-count-editor { display: flex; min-width: 0; }
.workbench :deep(.package-count-editor .el-input-number) { width: 100%; min-width: 0; }
.assign-dialog p { margin: 0 0 10px; }
.assign-dialog :deep(.el-input-number) { width: 100%; }
@media (max-width: 760px) { .workbench-command-bar,.header-actions { width: 100%; flex-direction: column; align-items: stretch; } .workbench-identities { flex-direction: column; align-items: stretch; gap: 10px; } .summary-band,.capacity-grid { grid-template-columns: 1fr; } .meter-title { align-items: flex-start; flex-direction: column; } .header-actions .el-button { min-height: 44px; margin-left: 0; } }