diff --git a/furniture-3d-system/next.config.js b/furniture-3d-system/next.config.js index 45485f59..86647a37 100644 --- a/furniture-3d-system/next.config.js +++ b/furniture-3d-system/next.config.js @@ -86,7 +86,7 @@ const nextConfig = { turbopack: {}, // 本地开发允许 localhost 和 127.0.0.1 复用同一套 dev 资源,避免 UI 改动只在其中一个地址生效 - allowedDevOrigins: ['localhost', '127.0.0.1'], + allowedDevOrigins: ['localhost', '127.0.0.1', '192.168.42.134'], // 图像优化配置 images: { diff --git a/furniture-3d-system/src/app/intake/IntakeClient.tsx b/furniture-3d-system/src/app/intake/IntakeClient.tsx index 2c1f8aeb..83de7990 100644 --- a/furniture-3d-system/src/app/intake/IntakeClient.tsx +++ b/furniture-3d-system/src/app/intake/IntakeClient.tsx @@ -266,22 +266,33 @@ function FormalIntakeWorkbench({ onToggle={() => onToggle('pending')} >
- {skuList.slice(0, 3).map((sku) => ( -
-
-
-

{sku.code}

-

{sku.name}

-
- - {sku.status} - -
+ {skuList.length === 0 ? ( +
+ 当前还没有待执行的 SKU。
- ))} + ) : ( + skuList.slice(0, 3).map((sku) => ( +
+
+
+

+ SKU编码:{sku.code} +

+

SKU名称:{sku.name}

+
+ + {sku.status} + +
+
+ +
+
+ )) + )}
@@ -292,7 +303,17 @@ function FormalIntakeWorkbench({ expanded={activeSection === 'components'} onToggle={() => onToggle('components')} > -
点击后在左侧查看详细配件内容。
+
+ {COMPONENT_LABELS.map((label) => ( +
+

{label}:编码

+

点击后在左侧查看详细内容

+
+ ))} +
onToggle('picking')} > -
点击后在左侧查看拣货打印预览。
+
+
+ 这里会显示 SKU编码、配件编码、库位、数量。先看表格预览,没问题再打印。 +
+
+ + +
+
onToggle('brand')} > -
点击后在左侧查看品牌物料明细。
+
+
+

品牌识别结果

+

根据 SKU 前缀自动识别

+
+ {BRAND_FILES.map((item) => ( +
+ {item} + +
+ ))} +
onToggle('packaging')} > -
点击后左侧切换成 3D 包装预览。
+
+
+

包装方案状态

+

点击后左侧切换成 3D 包装预览

+
+
+ + + + +
+
) diff --git a/furniture-3d-system/src/app/warehouse/WarehouseClient.tsx b/furniture-3d-system/src/app/warehouse/WarehouseClient.tsx index d26d572c..9803b8b0 100644 --- a/furniture-3d-system/src/app/warehouse/WarehouseClient.tsx +++ b/furniture-3d-system/src/app/warehouse/WarehouseClient.tsx @@ -1,18 +1,28 @@ 'use client' import { startTransition, useState } from 'react' -import Link from 'next/link' -import { ArrowRight, Boxes, MapPinned, Package, Plus, Warehouse as WarehouseIcon } from 'lucide-react' +import { + Boxes, + MapPinned, + Package, + Plus, + Printer, + Search, + Warehouse as WarehouseIcon, +} from 'lucide-react' import { Badge } from '@/components/ui/Badge' import Button from '@/components/ui/Button' import Input, { Textarea } from '@/components/ui/Input' import Modal from '@/components/ui/Modal' +import Select from '@/components/ui/Select' import { PlatformSplitLayout } from '@/components/platform/PlatformSplitLayout' import { AccordionSection } from '@/components/platform/AccordionSection' import type { PlatformMetricItem } from '@/components/platform/types' import { createWarehouseLocation } from '@/lib/open-product/platform-api' import type { WarehouseOverviewDTO } from '@/server/services' +type WarehouseSection = 'location' | 'parts-sku' | 'product-sku' | 'brand' | null + interface WarehouseClientProps { initialOverview: WarehouseOverviewDTO user: { @@ -26,8 +36,13 @@ interface WarehouseClientProps { metrics: PlatformMetricItem[] } +function toggleSection(current: WarehouseSection, section: Exclude): WarehouseSection { + return current === section ? null : section +} + export default function WarehouseClient({ initialOverview, user, metrics }: WarehouseClientProps) { const [overview, setOverview] = useState(initialOverview) + const [activeSection, setActiveSection] = useState(null) const [locationForm, setLocationForm] = useState({ code: '', name: '', @@ -44,37 +59,32 @@ export default function WarehouseClient({ initialOverview, user, metrics }: Ware text: string } | null>(null) + // 配件 SKU 搜索 + const [partsSearchMode, setPartsSearchMode] = useState<'barcode' | 'location'>('barcode') + const [partsSearchValue, setPartsSearchValue] = useState('') + + // 成品 SKU 搜索 + const [productSkuSearch, setProductSkuSearch] = useState('') + + // 品牌选择 + const [selectedBrand, setSelectedBrand] = useState('') + async function handleCreateLocation() { setSubmitting(true) setFeedback(null) try { const location = await createWarehouseLocation(locationForm) - startTransition(() => { setOverview((current) => ({ ...current, locations: [...current.locations, location], })) - setLocationForm({ - code: '', - name: '', - zone: '', - aisle: '', - shelf: '', - bin: '', - notes: '', - }) + setLocationForm({ code: '', name: '', zone: '', aisle: '', shelf: '', bin: '', notes: '' }) setLocationModalOpen(false) - setFeedback({ - tone: 'success', - text: '库位已创建,后续正式入库时即可直接选用。', - }) + setFeedback({ tone: 'success', text: '库位已创建,后续正式入库时即可直接选用。' }) }) } catch (error) { - setFeedback({ - tone: 'error', - text: error instanceof Error ? error.message : '库位创建失败,请稍后重试', - }) + setFeedback({ tone: 'error', text: error instanceof Error ? error.message : '库位创建失败,请稍后重试' }) } finally { setSubmitting(false) } @@ -87,210 +97,343 @@ export default function WarehouseClient({ initialOverview, user, metrics }: Ware overview.skuStock.reduce((sum, item) => sum + item.stock, 0) + overview.packagedItems.reduce((sum, item) => sum + item.stockQuantity, 0) - return ( - -

- 统计概览 -

-

- 一期只管理正式 SKU、包装成品、库存数量和基础库位。复杂出入库流水、调拨和盘点等完整 WMS 能力,留到后续阶段再进入。 -

+ // ========== 左侧详情内容 ========== -
-
-

库位数

-

{locationCount}

-
-
-

正式 SKU

-

{skuCount}

-
-
-

包装成品

-

{packagedCount}

-
-
-

总库存

-

{totalStock}

-
+ let leftContent: React.ReactNode = ( +
+
+

点击右侧模块查看详情

+
+
+ ) + + if (activeSection === 'location') { + leftContent = ( +
+
+
+

库位数

+

{locationCount}

- -
-

- 右侧面板可展开各模块查看详情或新增库位。 -

+
+

正式 SKU

+

{skuCount}

+
+
+

包装成品

+

{packagedCount}

+
+
+

总库存

+

{totalStock}

- } - rightContent={ - <> - {/* 库位管理:新增表单 + 现有列表,默认展开 */} - } - defaultExpanded - aside={ - - {locationCount} 个库位 - - } + +
+

库位列表

+ +
+ + {overview.locations.length === 0 ? ( +
+ 还没有库位。点击「新增库位」创建一个正式库位,后续入库即可挂接。 +
+ ) : ( + overview.locations.map((location) => ( +
+
+
+

{location.name}

+

{location.code}

+
+ + {location.isActive ? '可用' : '停用'} + +
+

+ {location.zone || '未分区'} / {location.aisle || '未设巷道'} / {location.shelf || '未设货架'} / {location.bin || '未设箱位'} +

+
+ )) + )} +
+ ) + } else if (activeSection === 'parts-sku') { + leftContent = ( +
+

配件 SKU 库位管理

+

管理板材、钢架、五金、纸箱等配件的条码和库位绑定关系,方便仓库按条码拣货。

+ + {/* 搜索模式切换 */} +
+ + +
+ + {/* 搜索框 */} +
+
+ setPartsSearchValue(e.target.value)} + /> +
+ +
+ + {/* 配件主数据列表 */} +
+
+

配件主数据

+ +
+ {['台面', '桌腿', '拉杆', '五金', '纸箱'].map((part) => ( +
+
+
+

{part}

+

编码:{part}-001 · 库位:A-01-01

+
+ 已绑定 +
+
+ ))} +
+
+ ) + } else if (activeSection === 'product-sku') { + leftContent = ( +
+

成品 SKU 库位管理

+

组合后的 SKU 打包成成品后,放在哪个成品库位。支持查询和绑定。

+ + {/* 成品 SKU 搜索 */} + setProductSkuSearch(e.target.value)} + /> + + {/* 成品 SKU 列表 */} +
+

成品 SKU 列表

+
+ 成品 SKU 列表将从正式入库数据中自动获取。功能开发中。 +
+
+ + {/* 成品库位绑定 */} +
+

成品库位绑定

+
+ 选择成品 SKU 后,可绑定或修改其存放的成品库位。功能开发中。 +
+
+ + {/* 打包执行入口 */} +
+

打包执行

+
+
+

查 SKU

+

输入编码或扫码进入

+
+
+

打印条码明细

+

配件条码 + 拣货单

+
+
+

选品牌

+

自动带出品牌物料

+
+
+

3D 打包

+

对照方案装箱

+
+
+
+
+ ) + } else if (activeSection === 'brand') { + leftContent = ( +
+

品牌物料库位管理

+

根据品牌自动带出对应的说明书、铭牌、合格证、外箱印刷等物料,维护库位。

+ + {/* 品牌选择 */} + - setLocationForm((current) => ({ ...current, name: event.target.value })) - } + onChange={(event) => setLocationForm((current) => ({ ...current, name: event.target.value }))} placeholder="例如 成品区 A01" />
- - setLocationForm((current) => ({ ...current, zone: event.target.value })) - } - /> - - setLocationForm((current) => ({ ...current, aisle: event.target.value })) - } - /> - - setLocationForm((current) => ({ ...current, shelf: event.target.value })) - } - /> - - setLocationForm((current) => ({ ...current, bin: event.target.value })) - } - /> + setLocationForm((current) => ({ ...current, zone: event.target.value }))} /> + setLocationForm((current) => ({ ...current, aisle: event.target.value }))} /> + setLocationForm((current) => ({ ...current, shelf: event.target.value }))} /> + setLocationForm((current) => ({ ...current, bin: event.target.value }))} />