diff --git a/furniture-3d-system/src/app/intake/new-product-management/page.tsx b/furniture-3d-system/src/app/intake/new-product-management/page.tsx index e431bb65..ced4b8c2 100644 --- a/furniture-3d-system/src/app/intake/new-product-management/page.tsx +++ b/furniture-3d-system/src/app/intake/new-product-management/page.tsx @@ -1,39 +1,5 @@ -import { requireSession } from "@/lib/server-session"; -import { OA_BOARD_DEFAULT_TRACKED_STATUSES } from "@/server/services/oa-board.constants"; -import { - createEmptyOaBoardDashboard, - oaBoardService, -} from "@/server/services/oa-board.service"; -import NewProductManagementDashboard from "./NewProductManagementDashboard"; - -export const dynamic = "force-dynamic"; +import { redirect } from 'next/navigation' export default async function NewProductManagementPage() { - await requireSession("/login"); - - const result = await oaBoardService - .getDashboard({ - overallStatus: [...OA_BOARD_DEFAULT_TRACKED_STATUSES], - }) - .then((dashboard) => ({ - dashboard, - loadErrorMessage: null as string | null, - })) - .catch((error) => { - console.error("Failed to load new product management dashboard", error); - return { - dashboard: createEmptyOaBoardDashboard(), - loadErrorMessage: - error instanceof Error - ? `新品管理数据读取失败:${error.message}` - : "新品管理数据读取失败,请稍后重试。", - }; - }); - - return ( - - ); + redirect('/supply-chain/new-products/overview') } diff --git a/furniture-3d-system/src/app/supply-chain/components/supply-chain-tabs.tsx b/furniture-3d-system/src/app/supply-chain/components/supply-chain-tabs.tsx index 8f5f1a37..587580a3 100644 --- a/furniture-3d-system/src/app/supply-chain/components/supply-chain-tabs.tsx +++ b/furniture-3d-system/src/app/supply-chain/components/supply-chain-tabs.tsx @@ -90,6 +90,7 @@ export const SUPPLY_CHAIN_ROUTE_TITLES: Record = { '/supply-chain/database/product-archive': '产品全量档案', '/supply-chain/database/category-config': '类目配置', '/supply-chain/database/warehouse-config': '仓库配置', + '/supply-chain/new-products/overview': '新品经营总览', '/supply-chain/new-products/unified-table': '新品开发进度总表', '/supply-chain/new-products/sample-progress': '打样进度明细', '/supply-chain/purchase/daily-affairs': '日常事项', diff --git a/furniture-3d-system/src/app/supply-chain/config/supply-chain-menu.test.ts b/furniture-3d-system/src/app/supply-chain/config/supply-chain-menu.test.ts index c5c4266f..77f099b6 100644 --- a/furniture-3d-system/src/app/supply-chain/config/supply-chain-menu.test.ts +++ b/furniture-3d-system/src/app/supply-chain/config/supply-chain-menu.test.ts @@ -6,6 +6,11 @@ describe('supply chain menu', () => { expect(items).toEqual( expect.arrayContaining([ + expect.objectContaining({ + label: '新品经营总览', + module: '新品管理', + route: '/supply-chain/new-products/overview', + }), expect.objectContaining({ label: '新品开发进度总表', module: '新品管理', diff --git a/furniture-3d-system/src/app/supply-chain/config/supply-chain-menu.ts b/furniture-3d-system/src/app/supply-chain/config/supply-chain-menu.ts index e2fdf5b2..c2b4157a 100644 --- a/furniture-3d-system/src/app/supply-chain/config/supply-chain-menu.ts +++ b/furniture-3d-system/src/app/supply-chain/config/supply-chain-menu.ts @@ -54,6 +54,11 @@ export const SUPPLY_CHAIN_MENU: SupplyChainMenuModule[] = [ label: '新品管理', icon: 'PackagePlus', sections: [ + { + items: [ + { label: '新品经营总览', route: '/supply-chain/new-products/overview', targetKey: 'newProductOverview' }, + ], + }, { title: '公共数据源', items: [ diff --git a/furniture-3d-system/src/app/supply-chain/new-products/overview/page.tsx b/furniture-3d-system/src/app/supply-chain/new-products/overview/page.tsx new file mode 100644 index 00000000..39845d5c --- /dev/null +++ b/furniture-3d-system/src/app/supply-chain/new-products/overview/page.tsx @@ -0,0 +1,49 @@ +import { redirect } from 'next/navigation' +import NewProductManagementDashboard from '@/app/intake/new-product-management/NewProductManagementDashboard' +import { requireSession } from '@/lib/server-session' +import { OA_BOARD_DEFAULT_TRACKED_STATUSES } from '@/server/services/oa-board.constants' +import { + createEmptyOaBoardDashboard, + oaBoardService, +} from '@/server/services/oa-board.service' +import { supplyChainPermissionSettingsService } from '@/server/services/supply-chain-permission-settings.service' + +export const dynamic = 'force-dynamic' +export const metadata = { title: '新品经营总览 · 供应链中心' } + +export default async function NewProductOverviewPage() { + const { authUser } = await requireSession('/login') + const access = await supplyChainPermissionSettingsService.getUserAccess( + authUser, + 'newProductOverview', + ) + if (!access.view) redirect('/supply-chain') + + const result = await oaBoardService + .getDashboard({ + overallStatus: [...OA_BOARD_DEFAULT_TRACKED_STATUSES], + }) + .then((dashboard) => ({ + dashboard, + loadErrorMessage: null as string | null, + })) + .catch((error) => { + console.error('Failed to load supply chain new product overview', error) + return { + dashboard: createEmptyOaBoardDashboard(), + loadErrorMessage: + error instanceof Error + ? `新品管理数据读取失败:${error.message}` + : '新品管理数据读取失败,请稍后重试。', + } + }) + + return ( +
+ +
+ ) +} diff --git a/furniture-3d-system/src/app/users/components/SupplyChainPermissionWorkspace.tsx b/furniture-3d-system/src/app/users/components/SupplyChainPermissionWorkspace.tsx index 0c21195c..9e957d9f 100644 --- a/furniture-3d-system/src/app/users/components/SupplyChainPermissionWorkspace.tsx +++ b/furniture-3d-system/src/app/users/components/SupplyChainPermissionWorkspace.tsx @@ -22,6 +22,7 @@ const TARGET_ICONS: Record { }) it('maps new product pages to their permission nodes', () => { + expect( + getSupplyChainPermissionTargetForPath('/supply-chain/new-products/overview'), + ).toBe('newProductOverview') expect( getSupplyChainPermissionTargetForPath('/supply-chain/new-products/unified-table'), ).toBe('newProductUnifiedTable') diff --git a/furniture-3d-system/src/lib/supply-chain-permission-settings.ts b/furniture-3d-system/src/lib/supply-chain-permission-settings.ts index fac5c1db..5a8b0a12 100644 --- a/furniture-3d-system/src/lib/supply-chain-permission-settings.ts +++ b/furniture-3d-system/src/lib/supply-chain-permission-settings.ts @@ -19,6 +19,7 @@ export type SupplyChainPermissionTargetKey = | 'productArchive' | 'categoryConfig' | 'warehouseConfig' + | 'newProductOverview' | 'newProductUnifiedTable' | 'newProductSampleProgress' | 'purchaseDailyAffairs' @@ -67,6 +68,7 @@ export const SUPPLY_CHAIN_PERMISSION_TARGETS: SupplyChainPermissionTarget[] = [ { key: 'productArchive', label: '产品全量档案', description: '商品、供应链和运营档案' }, { key: 'categoryConfig', label: '类目配置', description: '产品全量档案类目维护' }, { key: 'warehouseConfig', label: '仓库配置', description: '出入库仓库维护' }, + { key: 'newProductOverview', label: '新品经营总览', description: '新品经营指标和阶段时效分析' }, { key: 'newProductUnifiedTable', label: '新品开发进度总表', description: '新品流程公共数据源' }, { key: 'newProductSampleProgress', label: '打样进度明细', description: '新品打样进度公共数据源' }, { key: 'purchaseDailyAffairs', label: '日常事项', description: '采购日常协作' }, @@ -85,6 +87,7 @@ export const SUPPLY_CHAIN_PERMISSION_TARGET_ROUTES: Partial< productArchive: '/supply-chain/database/product-archive', categoryConfig: '/supply-chain/database/category-config', warehouseConfig: '/supply-chain/database/warehouse-config', + newProductOverview: '/supply-chain/new-products/overview', newProductUnifiedTable: '/supply-chain/new-products/unified-table', newProductSampleProgress: '/supply-chain/new-products/sample-progress', purchaseDailyAffairs: '/supply-chain/purchase/daily-affairs', @@ -238,6 +241,7 @@ export function getSupplyChainPermissionTargetForPath(pathname: string) { if (pathname === '/supply-chain/database/product-archive') return 'productArchive' as const if (pathname === '/supply-chain/database/category-config') return 'categoryConfig' as const if (pathname === '/supply-chain/database/warehouse-config') return 'warehouseConfig' as const + if (pathname === '/supply-chain/new-products/overview') return 'newProductOverview' as const if (pathname === '/supply-chain/new-products/unified-table') return 'newProductUnifiedTable' as const if (pathname === '/supply-chain/new-products/sample-progress') return 'newProductSampleProgress' as const if (pathname === '/supply-chain/purchase/daily-affairs') return 'purchaseDailyAffairs' as const