From e909cbdc9449a11340e0e1ee66e344ec162ca8ef Mon Sep 17 00:00:00 2001 From: WuYongJie Date: Mon, 27 Jul 2026 10:22:59 +0800 Subject: [PATCH] =?UTF-8?q?refactor(bom-costing):=20=E6=94=B6=E7=B4=A7?= =?UTF-8?q?=E7=A9=BA=E6=80=81=E5=B7=A5=E4=BD=9C=E5=8F=B0=E5=B8=83=E5=B1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BomCostingWorkbenchClient.test.tsx | 10 +- .../bom-costing/BomCostingWorkbenchClient.tsx | 310 ++++++++++-------- 2 files changed, 183 insertions(+), 137 deletions(-) diff --git a/furniture-3d-system/src/app/bom-costing/BomCostingWorkbenchClient.test.tsx b/furniture-3d-system/src/app/bom-costing/BomCostingWorkbenchClient.test.tsx index 85d70ebb..39f9d28e 100644 --- a/furniture-3d-system/src/app/bom-costing/BomCostingWorkbenchClient.test.tsx +++ b/furniture-3d-system/src/app/bom-costing/BomCostingWorkbenchClient.test.tsx @@ -6,7 +6,7 @@ jest.mock('@/components/platform/AssetWorkbenchEmptyBackdrop', () => ({ })) describe('BomCostingWorkbenchClient', () => { - it('生产服务未接入时保留完整工作台,但明确禁用分析按钮', () => { + it('生产服务未接入且没有案例时只展示紧凑入口', () => { render( { expect(screen.getByText('分析服务未接入')).toBeInTheDocument() expect(screen.getByRole('button', { name: /开始核算/ })).toBeDisabled() expect(screen.getByText(/目标误差 ≤10%/)).toBeInTheDocument() - expect(screen.getByText('概念模型服务未接入')).toBeInTheDocument() + expect(screen.getByText('竞品分析服务尚未接入')).toBeInTheDocument() + expect(screen.queryByText('核算记录')).not.toBeInTheDocument() + expect(screen.queryByText('成本汇总')).not.toBeInTheDocument() + expect(screen.queryByText('概念模型服务未接入')).not.toBeInTheDocument() + expect(screen.queryByTestId('empty-backdrop')).not.toBeInTheDocument() }) it('开发 fixture 结果支持 SKU 切换并联动 BOM 与成本', async () => { @@ -196,6 +200,8 @@ describe('BomCostingWorkbenchClient', () => { ) expect(await screen.findByText('桌面板')).toBeInTheDocument() + expect(screen.getByText('成本汇总')).toBeInTheDocument() + expect(screen.getByText('概念模型服务未接入')).toBeInTheDocument() fireEvent.click(screen.getByRole('button', { name: '白色 120cm' })) expect(screen.getByText('白色桌面板')).toBeInTheDocument() expect(screen.getAllByText('¥92.00').length).toBeGreaterThan(0) diff --git a/furniture-3d-system/src/app/bom-costing/BomCostingWorkbenchClient.tsx b/furniture-3d-system/src/app/bom-costing/BomCostingWorkbenchClient.tsx index 4da87950..b6cff1ec 100644 --- a/furniture-3d-system/src/app/bom-costing/BomCostingWorkbenchClient.tsx +++ b/furniture-3d-system/src/app/bom-costing/BomCostingWorkbenchClient.tsx @@ -7,7 +7,6 @@ import { CheckCircle2, ChevronRight, CircleAlert, - Clock3, ExternalLink, Link2, PackageSearch, @@ -173,12 +172,16 @@ export default function BomCostingWorkbenchClient({ } } - const modelStatus = initialCapabilities.modelingConfigured - ? '概念模型服务可用' - : '概念模型服务未接入' + const hasCases = cases.length > 0 + const hasSelectedSku = selectedSku !== null + const workbenchGridClassName = hasSelectedSku + ? 'lg:grid-cols-[248px_minmax(0,1fr)_310px]' + : hasCases + ? 'lg:grid-cols-[248px_minmax(0,1fr)]' + : 'grid-cols-1' return ( -
+
-
-
+
+
-
-

BOM核算

-

- 预计出厂成本 · 目标误差 ≤{initialCapabilities.targetErrorPercent}% +

+
+

BOM核算

+ + {initialCapabilities.analysisConfigured ? ( + + ) : ( + + )} + + {initialCapabilities.analysisConfigured + ? '分析服务可用' + : '分析服务未接入'} + + +
+

+ 出厂成本预估 · 目标误差 ≤{initialCapabilities.targetErrorPercent}%

-
+
setSourceUrl(event.target.value)} @@ -223,35 +247,24 @@ export default function BomCostingWorkbenchClient({ 开始核算
- -
- {initialCapabilities.analysisConfigured ? ( - - ) : ( - - )} - {initialCapabilities.analysisConfigured - ? '分析服务已接入' - : '分析服务未接入'} -
-
- + ) : null}
{selectedSku ? ( -
+
@@ -428,101 +436,133 @@ export default function BomCostingWorkbenchClient({
+ ) : hasCases ? ( +
+
+ {loadingCaseId ? ( + + ) : ( + + )} +

+ {loadingCaseId ? '正在加载核算结果' : '选择核算记录'} +

+

+ {loadingCaseId + ? '正在读取 SKU、BOM 与成本数据' + : '从记录中选择一项,查看对应 SKU 的 BOM 与成本'} +

+
+
) : ( -
- -
- -

选择核算记录

-

- 分析完成后,这里按 SKU 展开部件、用量与资料库价格匹配结果。 +

+
+
+ +
+

+ {initialCapabilities.analysisConfigured + ? '粘贴竞品链接开始核算' + : '竞品分析服务尚未接入'} +

+

+ {initialCapabilities.analysisConfigured + ? '完成后将按 SKU 展开部件用量、资料库价格匹配与预计出厂成本' + : '服务接入后,可按 SKU 核算材料、加工、人工与包材成本'}

)}
- +

+ 含材料、加工、人工、包材和损耗,不含税费、物流、平台佣金及营销费用。 +

+ + +
+

规格摘要

+
+ 成品尺寸 + + {[selectedSku.lengthMm, selectedSku.widthMm, selectedSku.heightMm] + .map((value) => value ?? '--') + .join(' × ')} + + 产品重量 + + {formatMetric(selectedSku.weightKg, 'kg')} + + 包装尺寸 + + {[ + selectedSku.packageLengthMm, + selectedSku.packageWidthMm, + selectedSku.packageHeightMm, + ] + .map((value) => value ?? '--') + .join(' × ')} + + 包装重量 + + {formatMetric(selectedSku.packageWeightKg, 'kg')} + +
+
+ +
+

概念模型

+ {initialCapabilities.modelingConfigured ? ( +
+ +
+ + 概念模型待生成 +
+
+ ) : ( +
+ + + 概念模型服务未接入 + +
+ )} +
+ + ) : null}
)