From d620d5d857ccf6db637c778b23939fab5e7b6034 Mon Sep 17 00:00:00 2001 From: zlwu <704541015@qq.com> Date: Tue, 28 Jul 2026 13:35:59 +0800 Subject: [PATCH] feat(web-admin): enable copy-first and batch slot fill on cell product create Keep inbound product-lines UX consistent with task output dialog. Co-authored-by: Cursor --- .../views/production/cell-product/index.vue | 73 ++++++++++++++++++- 1 file changed, 71 insertions(+), 2 deletions(-) diff --git a/web-admin/src/views/production/cell-product/index.vue b/web-admin/src/views/production/cell-product/index.vue index 62406a9f..7a5d9589 100644 --- a/web-admin/src/views/production/cell-product/index.vue +++ b/web-admin/src/views/production/cell-product/index.vue @@ -471,6 +471,16 @@
入库明细 {{ productLinesHint }} +
+ + + 复制首行属性 + + + + 批量填储物格 + +
+ + ([createEmptyProductLine()]) + const batchSlotFillVisible = ref(false) + + const emptyStorageSlotLineCount = computed( + () => productLines.value.filter((l) => !String(l.storageSlotId || '').trim()).length + ) + + const formUsedStorageSlotIds = computed(() => + productLines.value.map((l) => l.storageSlotId).filter((id) => String(id || '').trim()) + ) + + function handleCopyFirstLineAttrs() { + const r = copyFirstProductLineAttrs(productLines.value) + if (!r.ok) { + ElMessage.warning(r.message) + return + } + ElMessage.success(`已将首行属性复制到其余 ${r.filledCount} 行`) + } + + function openBatchSlotFill() { + if (emptyStorageSlotLineCount.value <= 0) { + ElMessage.warning('没有可填充的空行') + return + } + batchSlotFillVisible.value = true + } + + function onBatchSlotFilled(payload: { + slotIds: string[] + options: Array<{ id: string; name: string; facilityNodeId?: string }> + }) { + const n = applySlotIdsToEmptyLines(productLines.value, payload.slotIds) + storageSlotOptions.value = ensureStorageSlotsInOptions( + storageSlotOptions.value, + payload.options + ) + ElMessage.success(`已为 ${n} 行填充储物格`) + } const formRules = { productCode: [{ required: true, message: '请输入产品编码', trigger: 'blur' }], @@ -1874,7 +1936,7 @@ .product-lines-head { display: flex; - align-items: baseline; + align-items: center; flex-wrap: wrap; gap: 8px; margin-bottom: 10px; @@ -1886,6 +1948,13 @@ color: var(--mint-text, #334155); } + .product-lines-actions { + display: flex; + flex-wrap: wrap; + gap: 8px; + margin-left: auto; + } + .product-lines-table { width: 100%; }