diff --git a/src/app/asset-center/packaging-materials/PackagingMaterialsClient.tsx b/src/app/asset-center/packaging-materials/PackagingMaterialsClient.tsx index 8bf89d97..30369695 100644 --- a/src/app/asset-center/packaging-materials/PackagingMaterialsClient.tsx +++ b/src/app/asset-center/packaging-materials/PackagingMaterialsClient.tsx @@ -1,6 +1,6 @@ 'use client' -import { useCallback, useMemo, useState, useRef, useEffect } from 'react' +import { useCallback, useMemo, useState, useRef } from 'react' import Link from 'next/link' import { Badge } from '@/components/ui/Badge' import Button from '@/components/ui/Button' @@ -12,7 +12,6 @@ import { Search, ArrowLeft, ChevronRight, - Trash2, Copy, ToggleLeft, ToggleRight, @@ -146,7 +145,7 @@ function getStatusLabel(status: string) { } /* ============================================================ - * Drag-to-resize hook + * Drag-to-resize hook — supports N columns * ============================================================ */ function useColumnResize(initialWidths: number[]) { @@ -163,7 +162,7 @@ function useColumnResize(initialWidths: number[]) { const i = dragging.current.index setWidths((prev) => { const next = [...prev] - const minW = 120 + const minW = 100 next[i] = Math.max(minW, dragging.current!.startWidths[i] + dx) if (i + 1 < next.length) { next[i + 1] = Math.max(minW, dragging.current!.startWidths[i + 1] - dx) @@ -185,6 +184,19 @@ function useColumnResize(initialWidths: number[]) { return { widths, onMouseDown } } +/* ============================================================ + * Resize Handle component + * ============================================================ */ + +function ResizeHandle({ onMouseDown }: { onMouseDown: (e: React.MouseEvent) => void }) { + return ( +
+ ) +} + /* ============================================================ * Main Client Component * ============================================================ */ @@ -212,28 +224,8 @@ export default function PackagingMaterialsClient({ const [newFamilyLevel1, setNewFamilyLevel1] = useState('outer') const [newFamilyLevel2, setNewFamilyLevel2] = useState('carton') - // Resizable columns: [L1, L2, List+Detail] - const { widths: colWidths, onMouseDown: onColResize } = useColumnResize([150, 150, 600]) - // Vertical split within column 3: [list%, detail%] (as pixel heights) - const [listHeight, setListHeight] = useState(320) - const vDragging = useRef<{ startY: number; startH: number } | null>(null) - - const onVResizeDown = useCallback((e: React.MouseEvent) => { - e.preventDefault() - vDragging.current = { startY: e.clientY, startH: listHeight } - const onMove = (ev: MouseEvent) => { - if (!vDragging.current) return - const dy = ev.clientY - vDragging.current.startY - setListHeight(Math.max(120, vDragging.current.startH + dy)) - } - const onUp = () => { - vDragging.current = null - window.removeEventListener('mousemove', onMove) - window.removeEventListener('mouseup', onUp) - } - window.addEventListener('mousemove', onMove) - window.addEventListener('mouseup', onUp) - }, [listHeight]) + // 4 resizable columns: [L1, L2, List, Detail] + const { widths: colWidths, onMouseDown: onColResize } = useColumnResize([140, 140, 400, 400]) // ---- Filtered data ---- const filteredFamilies = useMemo(() => { @@ -245,7 +237,6 @@ export default function PackagingMaterialsClient({ [filteredFamilies], ) - // L2 list for selected L1 const l2Categories = useMemo( () => LEVEL2_BY_LEVEL1[selectedLevel1] ?? [], [selectedLevel1], @@ -420,7 +411,6 @@ export default function PackagingMaterialsClient({ [], ) - // ---- Selected variant for preview ---- const selectedVariant = useMemo( () => variants.find((v) => v.id === selectedVariantId) ?? null, [variants, selectedVariantId], @@ -428,7 +418,7 @@ export default function PackagingMaterialsClient({ return (
- {/* ====== Top Header ====== */} + {/* ====== Top Header & Toolbar ====== */}
@@ -442,13 +432,10 @@ export default function PackagingMaterialsClient({
-

- 包材资料库 -

+

包材资料库

- {/* Action toolbar */}
{stats.families} 品类 @@ -475,11 +462,11 @@ export default function PackagingMaterialsClient({
- {/* ====== Three-column body ====== */} + {/* ====== Four-column body ====== */}
- {/* Column 1: L1 Categories */} + {/* Column 1: L1 */}
@@ -494,10 +481,7 @@ export default function PackagingMaterialsClient({ return (
- {/* Resize handle 1 */} -
onColResize(0, e)} - /> + onColResize(0, e)} /> - {/* Column 2: L2 Categories */} + {/* Column 2: L2 */}
@@ -562,7 +542,6 @@ export default function PackagingMaterialsClient({ ) })} - {l2Categories.length === 0 && (

请先选择一级分类 @@ -571,186 +550,163 @@ export default function PackagingMaterialsClient({

- {/* Resize handle 2 */} + onColResize(1, e)} /> + + {/* Column 3: Material List */}
onColResize(1, e)} - /> - - {/* Column 3: List + Detail (vertical split) */} -
- {/* ---- List area ---- */} -
- {/* Search bar */} -
-
- - setSearchQuery(e.target.value)} - placeholder="搜索编码或名称..." - className="w-full rounded-apple-md border border-black/10 bg-white/80 pl-8 pr-3 py-1.5 text-sm placeholder:text-apple-label-tertiary focus:outline-none focus:ring-1 focus:ring-apple-blue/40" - /> -
- setSearchQuery(e.target.value)} + placeholder="搜索编码或名称..." + className="w-full rounded-apple-md border border-black/10 bg-white/80 pl-8 pr-3 py-1.5 text-sm placeholder:text-apple-label-tertiary focus:outline-none focus:ring-1 focus:ring-apple-blue/40" /> - {filteredVariants.length} 条 -
- - {/* List */} -
- {filteredVariants.length === 0 ? ( -
- -

暂无包材记录

-

选择品类后点击"新增包材"

-
- ) : ( - filteredVariants.map((variant) => { - const isSelected = selectedVariantId === variant.id - const family = families.find((f) => f.id === variant.assetFamilyId) - const level2Key = getLevel2FromFamily(family?.metadata ?? null) - const level2Label = getLevel2Label(level2Key) - const dims = (variant.dimensions ?? {}) as Record - const hasDims = dims.length || dims.width || dims.height || dims.thickness - - return ( -
setSelectedVariantId(variant.id)} - onDoubleClick={() => handleEdit(variant)} - className={cn( - 'rounded-apple-lg border px-3 py-2 text-left transition cursor-pointer group', - isSelected - ? 'border-apple-blue/30 bg-apple-blue/6' - : 'border-transparent hover:border-black/5 hover:bg-white/80', - )} - > -
-
-

- {variant.name} -

-
- {variant.code} - {level2Label !== '未分类' && ( - - {level2Label} - - )} -
-
-
- - {getStatusLabel(variant.status)} - -
-
- -
- {hasDims && ( - {dims.length ?? 0} × {dims.width ?? 0} × {dims.height ?? 0} mm - )} - {variant.costPrice != null && ¥{variant.costPrice}} - {variant.weightKg != null && {variant.weightKg} kg} -
-
- ) - }) - )}
+ setNewFamilyCode(e.target.value)} - placeholder="如 CARTON" - /> - setNewFamilyName(e.target.value)} - placeholder="如 纸箱" - /> + setNewFamilyCode(e.target.value)} placeholder="如 CARTON" /> + setNewFamilyName(e.target.value)} placeholder="如 纸箱" />
- - + +
@@ -857,9 +792,7 @@ function VariantPreview({

{variant.name}

{variant.code} - - {getStatusLabel(variant.status)} - + {getStatusLabel(variant.status)}
{level1Key && {getLevel1Label(level1Key)}} @@ -974,45 +907,27 @@ function DetailEditor({
)} - {/* 基础信息 */}
-

- 基础信息 -

- ({ value: f.id, label: f.name }))} - onChange={(e) => onChange({ assetFamilyId: e.target.value })} - /> + onChange={(e) => onChange({ assetFamilyId: e.target.value })} />
onChange({ code: e.target.value })} placeholder="CTN-1200" /> onChange({ name: e.target.value })} placeholder="纸箱 1200" />
- onChange({ unit: e.target.value })} /> + onChange({ length: e.target.value })} /> onChange({ width: e.target.value })} /> @@ -1025,45 +940,30 @@ function DetailEditor({
- {/* 品类模板 */} {templateFields.length > 0 && (
-

- 品类规格 -

+

品类规格

{templateFields.map((field) => ( - onTemplateFieldChange(field.key, value)} - /> + onTemplateFieldChange(field.key, value)} /> ))}
)} - {/* 成本 */}
-

- 成本 -

+

成本

onChange({ costPrice: e.target.value })} /> onChange({ sizeLabel: e.target.value })} placeholder="1200x600" />
- {/* 自定义属性 */}
-

- 自定义属性 -

- +

自定义属性

+
{material.customAttributes.map((attr, index) => (
@@ -1074,10 +974,8 @@ function DetailEditor({ ))}
- {/* 备注 */}