From 04838e3f74e465b25ca23d3b089f2b8391193b87 Mon Sep 17 00:00:00 2001 From: WuYongJie Date: Tue, 28 Apr 2026 10:09:05 +0800 Subject: [PATCH] feat: polish intake detail navigation --- .../src/app/intake/IntakeClient.test.tsx | 12 +++- .../src/app/intake/IntakeClient.tsx | 57 ++++++++++++----- .../NonIntegratedDetailClient.test.tsx | 23 +++++-- .../NonIntegratedDetailClient.tsx | 61 ++++++++++--------- .../non-integrated/nonIntegratedStorage.ts | 10 +++ .../src/components/layout/AppShell.tsx | 16 +++-- .../layout/__tests__/AppShell.test.tsx | 35 +++++++++-- 7 files changed, 156 insertions(+), 58 deletions(-) diff --git a/furniture-3d-system/src/app/intake/IntakeClient.test.tsx b/furniture-3d-system/src/app/intake/IntakeClient.test.tsx index 7f5dced8..eb05149b 100644 --- a/furniture-3d-system/src/app/intake/IntakeClient.test.tsx +++ b/furniture-3d-system/src/app/intake/IntakeClient.test.tsx @@ -6,6 +6,7 @@ import type { ReactNode } from 'react' import IntakeClient from './IntakeClient' import { createDefaultDocumentWorkspaceConfirmations, + getNonIntegratedDocumentWorkspaceCategoryLabel, NON_INTEGRATED_BRAND_PREFIX_MAP, NON_INTEGRATED_DOCUMENT_WORKSPACE_CATEGORIES, NON_INTEGRATED_STORAGE_KEY, @@ -544,11 +545,18 @@ describe('IntakeClient', () => { expect(pendingRow).not.toBeNull() expect(within(checkedRow as HTMLElement).getByText('已检查')).toBeInTheDocument() expect(within(pendingRow as HTMLElement).getByText('待确认')).toBeInTheDocument() + expect(screen.getByRole('columnheader', { name: '产品实拍' })).toBeInTheDocument() + expect(screen.getByRole('columnheader', { name: '产品资料' })).toBeInTheDocument() + expect(screen.getByRole('columnheader', { name: '仓库抽检' })).toBeInTheDocument() expect( - within(checkedRow as HTMLElement).getByLabelText(`${readyCategory}已检查且有数据`), + within(checkedRow as HTMLElement).getByLabelText( + `${getNonIntegratedDocumentWorkspaceCategoryLabel(readyCategory)}已检查且有数据`, + ), ).toBeInTheDocument() expect( - within(pendingRow as HTMLElement).getByLabelText(`${pendingCategory}未检查或无数据`), + within(pendingRow as HTMLElement).getByLabelText( + `${getNonIntegratedDocumentWorkspaceCategoryLabel(pendingCategory)}未检查或无数据`, + ), ).toBeInTheDocument() }) diff --git a/furniture-3d-system/src/app/intake/IntakeClient.tsx b/furniture-3d-system/src/app/intake/IntakeClient.tsx index 01d31437..aafc3e10 100644 --- a/furniture-3d-system/src/app/intake/IntakeClient.tsx +++ b/furniture-3d-system/src/app/intake/IntakeClient.tsx @@ -4,6 +4,7 @@ import Link from "next/link"; import { useRouter } from "next/navigation"; import { useEffect, useMemo, useState } from "react"; import { + Check, Copy, Eye, Layers3, @@ -13,6 +14,7 @@ import { Pencil, Printer, Trash2, + X as XIcon, } from "lucide-react"; import MaterialLibraryClient from "@/app/asset-center/material-library/MaterialLibraryClient"; import AccessoryLibraryPanel from "@/app/intake/AccessoryLibraryPanel"; @@ -35,6 +37,7 @@ import { NON_INTEGRATED_BRAND_PREFIX_MAP, NON_INTEGRATED_DOCUMENT_WORKSPACE_CATEGORIES, NON_INTEGRATED_PRODUCTS_UPDATED, + getNonIntegratedDocumentWorkspaceCategoryLabel, saveNonIntegratedProduct, type NonIntegratedProductRecord, } from "./non-integrated/nonIntegratedStorage"; @@ -148,6 +151,31 @@ function SpuLabel() { ); } +function DocumentStatusMark({ + category, + ready, +}: { + category: NonIntegratedDocumentStatusCategory; + ready: boolean; +}) { + const Icon = ready ? Check : XIcon; + const label = getNonIntegratedDocumentWorkspaceCategoryLabel(category); + + return ( + + + ); +} + type NonIntegratedDocumentStatusCategory = (typeof NON_INTEGRATED_DOCUMENT_WORKSPACE_CATEGORIES)[number]; @@ -156,6 +184,10 @@ const NON_INTEGRATED_DOCUMENT_STATUS_COLUMNS = [ ] as NonIntegratedDocumentStatusCategory[]; const PENDING_PAGE_SIZE = 25; +const TABLE_ACTION_BUTTON_BASE = + "!h-8 !min-h-8 !w-8 !rounded-md !px-0 !py-0 !shadow-none"; +const TABLE_ACTION_BUTTON_SECONDARY = `${TABLE_ACTION_BUTTON_BASE} !border-zinc-200 !bg-white !text-zinc-500 hover:!border-zinc-300 hover:!bg-zinc-50 hover:!text-zinc-950 focus:!border-zinc-400 disabled:!border-zinc-100 disabled:!bg-zinc-50 disabled:!text-zinc-300`; +const TABLE_ACTION_BUTTON_PRIMARY = `${TABLE_ACTION_BUTTON_BASE} !border-zinc-950 !bg-zinc-950 !text-white hover:!border-zinc-800 hover:!bg-zinc-800 focus:!border-zinc-600 disabled:!border-zinc-200 disabled:!bg-zinc-200 disabled:!text-zinc-400`; const BOM_LIBRARY_OPTIONS: { key: BomLibraryKey; @@ -1179,7 +1211,7 @@ function NonIntegratedPendingDetail({ key={category} className="min-w-[88px] px-3 py-2.5 text-center font-apple-medium whitespace-nowrap" > - {category} + {getNonIntegratedDocumentWorkspaceCategoryLabel(category)} ))} @@ -1280,16 +1312,10 @@ function NonIntegratedPendingDetail({ key={category} className="px-2 py-3 text-center align-middle" > - - {isReady ? "√" : "×"} - + ); }, @@ -1304,7 +1330,7 @@ function NonIntegratedPendingDetail({ - - ) : null} - {isDocumentWorkspaceMode ? ( + - ) : null} +

@@ -15791,6 +15768,34 @@ export default function NonIntegratedDetailClient({

+ {groupedUploadFiles.map(({ category, files }) => { const isActive = documentWorkspaceView === "document" && diff --git a/furniture-3d-system/src/app/intake/non-integrated/nonIntegratedStorage.ts b/furniture-3d-system/src/app/intake/non-integrated/nonIntegratedStorage.ts index a7d9dd40..35435b5d 100644 --- a/furniture-3d-system/src/app/intake/non-integrated/nonIntegratedStorage.ts +++ b/furniture-3d-system/src/app/intake/non-integrated/nonIntegratedStorage.ts @@ -47,6 +47,15 @@ export const NON_INTEGRATED_DOCUMENT_WORKSPACE_CATEGORIES = [ export type NonIntegratedDocumentWorkspaceCategory = (typeof NON_INTEGRATED_DOCUMENT_WORKSPACE_CATEGORIES)[number]; +export function getNonIntegratedDocumentWorkspaceCategoryLabel( + category: NonIntegratedDocumentWorkspaceCategory | string, +) { + if (category === "产品实拍图") return "产品实拍"; + if (category === "产品模型") return "产品资料"; + if (category === "检测报告") return "仓库抽检"; + return category; +} + export type NonIntegratedDocumentWorkspaceConfirmationMap = Record< NonIntegratedDocumentWorkspaceCategory, boolean @@ -78,6 +87,7 @@ const NON_INTEGRATED_UPLOAD_CATEGORY_MAP: Record = { 产品核价: "产品核价", 工厂质检: "工厂质检", 仓库质检: "工厂质检", + 仓库抽检: "检测报告", 产品资料: "产品模型", 产品实拍: "产品实拍图", 安装资料: "安装方式", diff --git a/furniture-3d-system/src/components/layout/AppShell.tsx b/furniture-3d-system/src/components/layout/AppShell.tsx index 6ebe40c5..c793ca57 100644 --- a/furniture-3d-system/src/components/layout/AppShell.tsx +++ b/furniture-3d-system/src/components/layout/AppShell.tsx @@ -44,10 +44,18 @@ export function AppShell({ children, user }: AppShellProps) { pathname === '/asset-center' || pathname.startsWith('/asset-center/') const isAssistedAssemblyRoute = pathname === '/assisted-assembly' || pathname.startsWith('/assisted-assembly/') + const isDraftGroupsRoute = pathname === '/draft-groups' || pathname.startsWith('/draft-groups/') const isIntakeRoute = pathname === '/intake' || pathname.startsWith('/intake/') const isWarehouseRoute = pathname === '/warehouse' || pathname.startsWith('/warehouse/') + const isWorkbenchShellRoute = + isHomeRoute || + isAssetCenterRoute || + isAssistedAssemblyRoute || + isDraftGroupsRoute || + isIntakeRoute || + isWarehouseRoute const shouldLockMainViewport = - isHomeRoute || isAssetCenterRoute || isAssistedAssemblyRoute || isIntakeRoute || isWarehouseRoute + isWorkbenchShellRoute useEffect(() => { if (!shouldLockMainViewport || typeof document === 'undefined') { @@ -82,12 +90,12 @@ export function AppShell({ children, user }: AppShellProps) {
- {!isHomeRoute && !isAssetCenterRoute && !isAssistedAssemblyRoute && } + {!isWorkbenchShellRoute && }
{ }) it('新平台主链页面渲染全局壳子', () => { - usePathnameMock.mockReturnValue('/intake') + usePathnameMock.mockReturnValue('/draft-groups') render( -
intake content
+
draft groups content
, ) - expect(screen.getByTestId('app-top-nav')).toBeInTheDocument() - expect(screen.getByTestId('app-side-nav')).toBeInTheDocument() - expect(screen.getByText('intake content')).toBeInTheDocument() + expect(screen.getByTestId('app-top-nav')).toHaveAttribute('data-variant', 'workbench') + expect(screen.queryByTestId('app-side-nav')).not.toBeInTheDocument() + expect(screen.getByText('draft groups content')).toBeInTheDocument() }) it('首页使用工作台壳子且不再渲染左侧旧导航', () => { @@ -92,4 +92,29 @@ describe('AppShell', () => { expect(screen.queryByTestId('app-side-nav')).not.toBeInTheDocument() expect(screen.getByText('assisted assembly content')).toBeInTheDocument() }) + + it('正式产品和仓库管理使用顶部工作台导航', () => { + usePathnameMock.mockReturnValue('/intake') + + const { rerender } = render( + +
intake content
+
, + ) + + expect(screen.getByTestId('app-top-nav')).toHaveAttribute('data-variant', 'workbench') + expect(screen.queryByTestId('app-side-nav')).not.toBeInTheDocument() + expect(screen.getByText('intake content')).toBeInTheDocument() + + usePathnameMock.mockReturnValue('/warehouse') + rerender( + +
warehouse content
+
, + ) + + expect(screen.getByTestId('app-top-nav')).toHaveAttribute('data-variant', 'workbench') + expect(screen.queryByTestId('app-side-nav')).not.toBeInTheDocument() + expect(screen.getByText('warehouse content')).toBeInTheDocument() + }) }) -- 2.47.2