Merge branch 'jskim-node' of origin into jskim-node

Resolve conflict in AppLayout.tsx - keep both sidebar collapse and hasPopMenus state

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
DDD1542
2026-04-09 11:14:00 +09:00
323 changed files with 251480 additions and 29399 deletions
+5 -2
View File
@@ -53,11 +53,14 @@ export function ImageUpload({
const [dragOver, setDragOver] = useState(false);
const fileRef = useRef<HTMLInputElement>(null);
// 이미지 URL 결정
// 이미지 URL 결정 (Next.js 프록시 우회 — 바이너리 스트림 500 에러 방지)
const apiBase = typeof window !== "undefined"
? (process.env.NEXT_PUBLIC_API_URL || "").replace(/\/api\/?$/, "")
: "";
const imageUrl = value
? (value.startsWith("http") || value.startsWith("/"))
? value
: `/api/files/preview/${value}`
: `${apiBase}/api/files/preview/${value}`
: null;
const handleUpload = useCallback(async (file: File) => {
@@ -95,6 +95,8 @@ const ADMIN_PAGE_REGISTRY: Record<string, React.ComponentType<any>> = {
// === COMPANY_7 (탑씰) ===
"/COMPANY_7/master-data/item-info": dynamic(() => import("@/app/(main)/COMPANY_7/master-data/item-info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/master-data/department": dynamic(() => import("@/app/(main)/COMPANY_7/master-data/department/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/master-data/company": dynamic(() => import("@/app/(main)/COMPANY_7/master-data/company/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/master-data/options": dynamic(() => import("@/app/(main)/COMPANY_7/master-data/options/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/sales/order": dynamic(() => import("@/app/(main)/COMPANY_7/sales/order/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/sales/customer": dynamic(() => import("@/app/(main)/COMPANY_7/sales/customer/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/sales/sales-item": dynamic(() => import("@/app/(main)/COMPANY_7/sales/sales-item/page"), { ssr: false, loading: LoadingFallback }),
@@ -105,11 +107,16 @@ const ADMIN_PAGE_REGISTRY: Record<string, React.ComponentType<any>> = {
"/COMPANY_7/production/process-info": dynamic(() => import("@/app/(main)/COMPANY_7/production/process-info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/production/work-instruction": dynamic(() => import("@/app/(main)/COMPANY_7/production/work-instruction/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/production/plan-management": dynamic(() => import("@/app/(main)/COMPANY_7/production/plan-management/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/production/bom": dynamic(() => import("@/app/(main)/COMPANY_7/production/bom/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/equipment/info": dynamic(() => import("@/app/(main)/COMPANY_7/equipment/info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/equipment/plc-settings": dynamic(() => import("@/app/(main)/COMPANY_7/equipment/plc-settings/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/logistics/material-status": dynamic(() => import("@/app/(main)/COMPANY_7/logistics/material-status/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/logistics/outbound": dynamic(() => import("@/app/(main)/COMPANY_7/logistics/outbound/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/logistics/receiving": dynamic(() => import("@/app/(main)/COMPANY_7/logistics/receiving/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/logistics/packaging": dynamic(() => import("@/app/(main)/COMPANY_7/logistics/packaging/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/logistics/info": dynamic(() => import("@/app/(main)/COMPANY_7/logistics/info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/logistics/inventory": dynamic(() => import("@/app/(main)/COMPANY_7/logistics/inventory/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/logistics/warehouse": dynamic(() => import("@/app/(main)/COMPANY_7/logistics/warehouse/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/outsourcing/subcontractor": dynamic(() => import("@/app/(main)/COMPANY_7/outsourcing/subcontractor/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/outsourcing/subcontractor-item": dynamic(() => import("@/app/(main)/COMPANY_7/outsourcing/subcontractor-item/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/design/project": dynamic(() => import("@/app/(main)/COMPANY_7/design/project/page"), { ssr: false, loading: LoadingFallback }),
@@ -128,12 +135,25 @@ const ADMIN_PAGE_REGISTRY: Record<string, React.ComponentType<any>> = {
"/COMPANY_16/sales/shipping-order": dynamic(() => import("@/app/(main)/COMPANY_16/sales/shipping-order/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_16/sales/shipping-plan": dynamic(() => import("@/app/(main)/COMPANY_16/sales/shipping-plan/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_16/sales/claim": dynamic(() => import("@/app/(main)/COMPANY_16/sales/claim/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_16/sales/quote": dynamic(() => import("@/app/(main)/COMPANY_16/sales/quote/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_16/production/process-info": dynamic(() => import("@/app/(main)/COMPANY_16/production/process-info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_16/production/work-instruction": dynamic(() => import("@/app/(main)/COMPANY_16/production/work-instruction/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_16/production/plan-management": dynamic(() => import("@/app/(main)/COMPANY_16/production/plan-management/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_16/production/bom": dynamic(() => import("@/app/(main)/COMPANY_16/production/bom/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_16/equipment/info": dynamic(() => import("@/app/(main)/COMPANY_16/equipment/info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_16/equipment/plc-settings": dynamic(() => import("@/app/(main)/COMPANY_16/equipment/plc-settings/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_16/monitoring/production": dynamic(() => import("@/app/(main)/COMPANY_16/monitoring/production/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_16/monitoring/equipment": dynamic(() => import("@/app/(main)/COMPANY_16/monitoring/equipment/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_16/monitoring/quality": dynamic(() => import("@/app/(main)/COMPANY_16/monitoring/quality/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/monitoring/production": dynamic(() => import("@/app/(main)/COMPANY_7/monitoring/production/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/monitoring/equipment": dynamic(() => import("@/app/(main)/COMPANY_7/monitoring/equipment/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/monitoring/quality": dynamic(() => import("@/app/(main)/COMPANY_7/monitoring/quality/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/purchase/order": dynamic(() => import("@/app/(main)/COMPANY_7/purchase/order/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/purchase/purchase-item": dynamic(() => import("@/app/(main)/COMPANY_7/purchase/purchase-item/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/purchase/supplier": dynamic(() => import("@/app/(main)/COMPANY_7/purchase/supplier/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/quality/inspection": dynamic(() => import("@/app/(main)/COMPANY_7/quality/inspection/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/quality/item-inspection": dynamic(() => import("@/app/(main)/COMPANY_7/quality/item-inspection/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_7/mold/info": dynamic(() => import("@/app/(main)/COMPANY_7/mold/info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_16/logistics/material-status": dynamic(() => import("@/app/(main)/COMPANY_16/logistics/material-status/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_16/logistics/outbound": dynamic(() => import("@/app/(main)/COMPANY_16/logistics/outbound/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_16/logistics/receiving": dynamic(() => import("@/app/(main)/COMPANY_16/logistics/receiving/page"), { ssr: false, loading: LoadingFallback }),
@@ -154,32 +174,212 @@ const ADMIN_PAGE_REGISTRY: Record<string, React.ComponentType<any>> = {
"/COMPANY_16/design/my-work": dynamic(() => import("@/app/(main)/COMPANY_16/design/my-work/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_16/design/design-request": dynamic(() => import("@/app/(main)/COMPANY_16/design/design-request/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_16/design/task-management": dynamic(() => import("@/app/(main)/COMPANY_16/design/task-management/page"), { ssr: false, loading: LoadingFallback }),
// === COMPANY_8 (대진산업) ===
"/COMPANY_8/master-data/options": dynamic(() => import("@/app/(main)/COMPANY_8/master-data/options/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/master-data/item-info": dynamic(() => import("@/app/(main)/COMPANY_8/master-data/item-info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/master-data/department": dynamic(() => import("@/app/(main)/COMPANY_8/master-data/department/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/master-data/company": dynamic(() => import("@/app/(main)/COMPANY_8/master-data/company/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/sales/order": dynamic(() => import("@/app/(main)/COMPANY_8/sales/order/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/sales/customer": dynamic(() => import("@/app/(main)/COMPANY_8/sales/customer/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/sales/sales-item": dynamic(() => import("@/app/(main)/COMPANY_8/sales/sales-item/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/sales/shipping-order": dynamic(() => import("@/app/(main)/COMPANY_8/sales/shipping-order/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/sales/shipping-plan": dynamic(() => import("@/app/(main)/COMPANY_8/sales/shipping-plan/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/sales/claim": dynamic(() => import("@/app/(main)/COMPANY_8/sales/claim/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/sales/quote": dynamic(() => import("@/app/(main)/COMPANY_8/sales/quote/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/production/process-info": dynamic(() => import("@/app/(main)/COMPANY_8/production/process-info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/production/work-instruction": dynamic(() => import("@/app/(main)/COMPANY_8/production/work-instruction/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/production/plan-management": dynamic(() => import("@/app/(main)/COMPANY_8/production/plan-management/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/production/bom": dynamic(() => import("@/app/(main)/COMPANY_8/production/bom/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/equipment/info": dynamic(() => import("@/app/(main)/COMPANY_8/equipment/info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/equipment/plc-settings": dynamic(() => import("@/app/(main)/COMPANY_8/equipment/plc-settings/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/monitoring/production": dynamic(() => import("@/app/(main)/COMPANY_8/monitoring/production/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/monitoring/equipment": dynamic(() => import("@/app/(main)/COMPANY_8/monitoring/equipment/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/monitoring/quality": dynamic(() => import("@/app/(main)/COMPANY_8/monitoring/quality/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/logistics/material-status": dynamic(() => import("@/app/(main)/COMPANY_8/logistics/material-status/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/logistics/outbound": dynamic(() => import("@/app/(main)/COMPANY_8/logistics/outbound/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/logistics/receiving": dynamic(() => import("@/app/(main)/COMPANY_8/logistics/receiving/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/logistics/packaging": dynamic(() => import("@/app/(main)/COMPANY_8/logistics/packaging/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/logistics/inventory": dynamic(() => import("@/app/(main)/COMPANY_8/logistics/inventory/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/logistics/warehouse": dynamic(() => import("@/app/(main)/COMPANY_8/logistics/warehouse/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/logistics/info": dynamic(() => import("@/app/(main)/COMPANY_8/logistics/info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/outsourcing/subcontractor": dynamic(() => import("@/app/(main)/COMPANY_8/outsourcing/subcontractor/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/outsourcing/subcontractor-item": dynamic(() => import("@/app/(main)/COMPANY_8/outsourcing/subcontractor-item/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/purchase/order": dynamic(() => import("@/app/(main)/COMPANY_8/purchase/order/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/purchase/purchase-item": dynamic(() => import("@/app/(main)/COMPANY_8/purchase/purchase-item/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/purchase/supplier": dynamic(() => import("@/app/(main)/COMPANY_8/purchase/supplier/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/quality/inspection": dynamic(() => import("@/app/(main)/COMPANY_8/quality/inspection/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/quality/item-inspection": dynamic(() => import("@/app/(main)/COMPANY_8/quality/item-inspection/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/mold/info": dynamic(() => import("@/app/(main)/COMPANY_8/mold/info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/design/project": dynamic(() => import("@/app/(main)/COMPANY_8/design/project/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/design/change-management": dynamic(() => import("@/app/(main)/COMPANY_8/design/change-management/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/design/my-work": dynamic(() => import("@/app/(main)/COMPANY_8/design/my-work/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/design/design-request": dynamic(() => import("@/app/(main)/COMPANY_8/design/design-request/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_8/design/task-management": dynamic(() => import("@/app/(main)/COMPANY_8/design/task-management/page"), { ssr: false, loading: LoadingFallback }),
// === COMPANY_10 (큐앤씨) ===
"/COMPANY_10/master-data/options": dynamic(() => import("@/app/(main)/COMPANY_10/master-data/options/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/master-data/item-info": dynamic(() => import("@/app/(main)/COMPANY_10/master-data/item-info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/master-data/department": dynamic(() => import("@/app/(main)/COMPANY_10/master-data/department/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/master-data/company": dynamic(() => import("@/app/(main)/COMPANY_10/master-data/company/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/sales/order": dynamic(() => import("@/app/(main)/COMPANY_10/sales/order/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/sales/customer": dynamic(() => import("@/app/(main)/COMPANY_10/sales/customer/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/sales/sales-item": dynamic(() => import("@/app/(main)/COMPANY_10/sales/sales-item/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/sales/shipping-order": dynamic(() => import("@/app/(main)/COMPANY_10/sales/shipping-order/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/sales/shipping-plan": dynamic(() => import("@/app/(main)/COMPANY_10/sales/shipping-plan/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/sales/claim": dynamic(() => import("@/app/(main)/COMPANY_10/sales/claim/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/sales/quote": dynamic(() => import("@/app/(main)/COMPANY_10/sales/quote/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/production/process-info": dynamic(() => import("@/app/(main)/COMPANY_10/production/process-info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/production/work-instruction": dynamic(() => import("@/app/(main)/COMPANY_10/production/work-instruction/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/production/plan-management": dynamic(() => import("@/app/(main)/COMPANY_10/production/plan-management/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/production/bom": dynamic(() => import("@/app/(main)/COMPANY_10/production/bom/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/equipment/info": dynamic(() => import("@/app/(main)/COMPANY_10/equipment/info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/equipment/plc-settings": dynamic(() => import("@/app/(main)/COMPANY_10/equipment/plc-settings/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/monitoring/production": dynamic(() => import("@/app/(main)/COMPANY_10/monitoring/production/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/monitoring/equipment": dynamic(() => import("@/app/(main)/COMPANY_10/monitoring/equipment/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/monitoring/quality": dynamic(() => import("@/app/(main)/COMPANY_10/monitoring/quality/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/logistics/material-status": dynamic(() => import("@/app/(main)/COMPANY_10/logistics/material-status/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/logistics/outbound": dynamic(() => import("@/app/(main)/COMPANY_10/logistics/outbound/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/logistics/receiving": dynamic(() => import("@/app/(main)/COMPANY_10/logistics/receiving/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/logistics/packaging": dynamic(() => import("@/app/(main)/COMPANY_10/logistics/packaging/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/logistics/inventory": dynamic(() => import("@/app/(main)/COMPANY_10/logistics/inventory/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/logistics/warehouse": dynamic(() => import("@/app/(main)/COMPANY_10/logistics/warehouse/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/logistics/info": dynamic(() => import("@/app/(main)/COMPANY_10/logistics/info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/outsourcing/subcontractor": dynamic(() => import("@/app/(main)/COMPANY_10/outsourcing/subcontractor/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/outsourcing/subcontractor-item": dynamic(() => import("@/app/(main)/COMPANY_10/outsourcing/subcontractor-item/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/purchase/order": dynamic(() => import("@/app/(main)/COMPANY_10/purchase/order/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/purchase/purchase-item": dynamic(() => import("@/app/(main)/COMPANY_10/purchase/purchase-item/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/purchase/supplier": dynamic(() => import("@/app/(main)/COMPANY_10/purchase/supplier/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/quality/inspection": dynamic(() => import("@/app/(main)/COMPANY_10/quality/inspection/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/quality/item-inspection": dynamic(() => import("@/app/(main)/COMPANY_10/quality/item-inspection/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/mold/info": dynamic(() => import("@/app/(main)/COMPANY_10/mold/info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/design/project": dynamic(() => import("@/app/(main)/COMPANY_10/design/project/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/design/change-management": dynamic(() => import("@/app/(main)/COMPANY_10/design/change-management/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/design/my-work": dynamic(() => import("@/app/(main)/COMPANY_10/design/my-work/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/design/design-request": dynamic(() => import("@/app/(main)/COMPANY_10/design/design-request/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_10/design/task-management": dynamic(() => import("@/app/(main)/COMPANY_10/design/task-management/page"), { ssr: false, loading: LoadingFallback }),
// === COMPANY_29 (시연용 회사) ===
"/COMPANY_29/master-data/options": dynamic(() => import("@/app/(main)/COMPANY_29/master-data/options/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/master-data/item-info": dynamic(() => import("@/app/(main)/COMPANY_29/master-data/item-info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/master-data/department": dynamic(() => import("@/app/(main)/COMPANY_29/master-data/department/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/master-data/company": dynamic(() => import("@/app/(main)/COMPANY_29/master-data/company/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/sales/order": dynamic(() => import("@/app/(main)/COMPANY_29/sales/order/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/sales/customer": dynamic(() => import("@/app/(main)/COMPANY_29/sales/customer/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/sales/sales-item": dynamic(() => import("@/app/(main)/COMPANY_29/sales/sales-item/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/sales/shipping-order": dynamic(() => import("@/app/(main)/COMPANY_29/sales/shipping-order/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/sales/shipping-plan": dynamic(() => import("@/app/(main)/COMPANY_29/sales/shipping-plan/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/sales/claim": dynamic(() => import("@/app/(main)/COMPANY_29/sales/claim/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/sales/quote": dynamic(() => import("@/app/(main)/COMPANY_29/sales/quote/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/production/process-info": dynamic(() => import("@/app/(main)/COMPANY_29/production/process-info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/production/work-instruction": dynamic(() => import("@/app/(main)/COMPANY_29/production/work-instruction/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/production/plan-management": dynamic(() => import("@/app/(main)/COMPANY_29/production/plan-management/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/production/bom": dynamic(() => import("@/app/(main)/COMPANY_29/production/bom/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/equipment/info": dynamic(() => import("@/app/(main)/COMPANY_29/equipment/info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/equipment/plc-settings": dynamic(() => import("@/app/(main)/COMPANY_29/equipment/plc-settings/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/monitoring/production": dynamic(() => import("@/app/(main)/COMPANY_29/monitoring/production/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/monitoring/equipment": dynamic(() => import("@/app/(main)/COMPANY_29/monitoring/equipment/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/monitoring/quality": dynamic(() => import("@/app/(main)/COMPANY_29/monitoring/quality/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/logistics/material-status": dynamic(() => import("@/app/(main)/COMPANY_29/logistics/material-status/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/logistics/outbound": dynamic(() => import("@/app/(main)/COMPANY_29/logistics/outbound/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/logistics/receiving": dynamic(() => import("@/app/(main)/COMPANY_29/logistics/receiving/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/logistics/packaging": dynamic(() => import("@/app/(main)/COMPANY_29/logistics/packaging/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/logistics/inventory": dynamic(() => import("@/app/(main)/COMPANY_29/logistics/inventory/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/logistics/warehouse": dynamic(() => import("@/app/(main)/COMPANY_29/logistics/warehouse/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/logistics/info": dynamic(() => import("@/app/(main)/COMPANY_29/logistics/info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/outsourcing/subcontractor": dynamic(() => import("@/app/(main)/COMPANY_29/outsourcing/subcontractor/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/outsourcing/subcontractor-item": dynamic(() => import("@/app/(main)/COMPANY_29/outsourcing/subcontractor-item/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/purchase/order": dynamic(() => import("@/app/(main)/COMPANY_29/purchase/order/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/purchase/purchase-item": dynamic(() => import("@/app/(main)/COMPANY_29/purchase/purchase-item/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/purchase/supplier": dynamic(() => import("@/app/(main)/COMPANY_29/purchase/supplier/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/quality/inspection": dynamic(() => import("@/app/(main)/COMPANY_29/quality/inspection/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/quality/item-inspection": dynamic(() => import("@/app/(main)/COMPANY_29/quality/item-inspection/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/mold/info": dynamic(() => import("@/app/(main)/COMPANY_29/mold/info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/design/project": dynamic(() => import("@/app/(main)/COMPANY_29/design/project/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/design/change-management": dynamic(() => import("@/app/(main)/COMPANY_29/design/change-management/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/design/my-work": dynamic(() => import("@/app/(main)/COMPANY_29/design/my-work/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/design/design-request": dynamic(() => import("@/app/(main)/COMPANY_29/design/design-request/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_29/design/task-management": dynamic(() => import("@/app/(main)/COMPANY_29/design/task-management/page"), { ssr: false, loading: LoadingFallback }),
// === COMPANY_9 (제일그라스) ===
"/COMPANY_9/master-data/item-info": dynamic(() => import("@/app/(main)/COMPANY_9/master-data/item-info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/master-data/department": dynamic(() => import("@/app/(main)/COMPANY_9/master-data/department/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/master-data/company": dynamic(() => import("@/app/(main)/COMPANY_9/master-data/company/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/master-data/options": dynamic(() => import("@/app/(main)/COMPANY_9/master-data/options/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/sales/order": dynamic(() => import("@/app/(main)/COMPANY_9/sales/order/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/sales/customer": dynamic(() => import("@/app/(main)/COMPANY_9/sales/customer/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/sales/sales-item": dynamic(() => import("@/app/(main)/COMPANY_9/sales/sales-item/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/sales/shipping-order": dynamic(() => import("@/app/(main)/COMPANY_9/sales/shipping-order/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/sales/shipping-plan": dynamic(() => import("@/app/(main)/COMPANY_9/sales/shipping-plan/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/sales/claim": dynamic(() => import("@/app/(main)/COMPANY_9/sales/claim/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/sales/quote": dynamic(() => import("@/app/(main)/COMPANY_9/sales/quote/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/production/process-info": dynamic(() => import("@/app/(main)/COMPANY_9/production/process-info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/production/work-instruction": dynamic(() => import("@/app/(main)/COMPANY_9/production/work-instruction/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/production/plan-management": dynamic(() => import("@/app/(main)/COMPANY_9/production/plan-management/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/production/bom": dynamic(() => import("@/app/(main)/COMPANY_9/production/bom/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/equipment/info": dynamic(() => import("@/app/(main)/COMPANY_9/equipment/info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/equipment/plc-settings": dynamic(() => import("@/app/(main)/COMPANY_9/equipment/plc-settings/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/monitoring/production": dynamic(() => import("@/app/(main)/COMPANY_9/monitoring/production/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/monitoring/equipment": dynamic(() => import("@/app/(main)/COMPANY_9/monitoring/equipment/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/monitoring/quality": dynamic(() => import("@/app/(main)/COMPANY_9/monitoring/quality/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/logistics/material-status": dynamic(() => import("@/app/(main)/COMPANY_9/logistics/material-status/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/logistics/outbound": dynamic(() => import("@/app/(main)/COMPANY_9/logistics/outbound/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/logistics/receiving": dynamic(() => import("@/app/(main)/COMPANY_9/logistics/receiving/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/logistics/packaging": dynamic(() => import("@/app/(main)/COMPANY_9/logistics/packaging/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/logistics/info": dynamic(() => import("@/app/(main)/COMPANY_9/logistics/info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/logistics/inventory": dynamic(() => import("@/app/(main)/COMPANY_9/logistics/inventory/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/logistics/warehouse": dynamic(() => import("@/app/(main)/COMPANY_9/logistics/warehouse/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/outsourcing/subcontractor": dynamic(() => import("@/app/(main)/COMPANY_9/outsourcing/subcontractor/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/outsourcing/subcontractor-item": dynamic(() => import("@/app/(main)/COMPANY_9/outsourcing/subcontractor-item/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/purchase/order": dynamic(() => import("@/app/(main)/COMPANY_9/purchase/order/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/purchase/purchase-item": dynamic(() => import("@/app/(main)/COMPANY_9/purchase/purchase-item/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/purchase/supplier": dynamic(() => import("@/app/(main)/COMPANY_9/purchase/supplier/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/quality/inspection": dynamic(() => import("@/app/(main)/COMPANY_9/quality/inspection/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/quality/item-inspection": dynamic(() => import("@/app/(main)/COMPANY_9/quality/item-inspection/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/mold/info": dynamic(() => import("@/app/(main)/COMPANY_9/mold/info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/design/project": dynamic(() => import("@/app/(main)/COMPANY_9/design/project/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/design/change-management": dynamic(() => import("@/app/(main)/COMPANY_9/design/change-management/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/design/my-work": dynamic(() => import("@/app/(main)/COMPANY_9/design/my-work/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/design/design-request": dynamic(() => import("@/app/(main)/COMPANY_9/design/design-request/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_9/design/task-management": dynamic(() => import("@/app/(main)/COMPANY_9/design/task-management/page"), { ssr: false, loading: LoadingFallback }),
// === COMPANY_30 ===
"/COMPANY_30/master-data/item-info": dynamic(() => import("@/app/(main)/COMPANY_30/master-data/item-info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/master-data/department": dynamic(() => import("@/app/(main)/COMPANY_30/master-data/department/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/master-data/company": dynamic(() => import("@/app/(main)/COMPANY_30/master-data/company/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/master-data/options": dynamic(() => import("@/app/(main)/COMPANY_30/master-data/options/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/sales/order": dynamic(() => import("@/app/(main)/COMPANY_30/sales/order/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/sales/customer": dynamic(() => import("@/app/(main)/COMPANY_30/sales/customer/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/sales/sales-item": dynamic(() => import("@/app/(main)/COMPANY_30/sales/sales-item/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/sales/shipping-order": dynamic(() => import("@/app/(main)/COMPANY_30/sales/shipping-order/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/sales/shipping-plan": dynamic(() => import("@/app/(main)/COMPANY_30/sales/shipping-plan/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/sales/claim": dynamic(() => import("@/app/(main)/COMPANY_30/sales/claim/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/sales/quote": dynamic(() => import("@/app/(main)/COMPANY_30/sales/quote/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/production/process-info": dynamic(() => import("@/app/(main)/COMPANY_30/production/process-info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/production/work-instruction": dynamic(() => import("@/app/(main)/COMPANY_30/production/work-instruction/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/production/plan-management": dynamic(() => import("@/app/(main)/COMPANY_30/production/plan-management/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/production/bom": dynamic(() => import("@/app/(main)/COMPANY_30/production/bom/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/equipment/info": dynamic(() => import("@/app/(main)/COMPANY_30/equipment/info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/equipment/plc-settings": dynamic(() => import("@/app/(main)/COMPANY_30/equipment/plc-settings/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/monitoring/production": dynamic(() => import("@/app/(main)/COMPANY_30/monitoring/production/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/monitoring/equipment": dynamic(() => import("@/app/(main)/COMPANY_30/monitoring/equipment/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/monitoring/quality": dynamic(() => import("@/app/(main)/COMPANY_30/monitoring/quality/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/logistics/material-status": dynamic(() => import("@/app/(main)/COMPANY_30/logistics/material-status/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/logistics/outbound": dynamic(() => import("@/app/(main)/COMPANY_30/logistics/outbound/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/logistics/receiving": dynamic(() => import("@/app/(main)/COMPANY_30/logistics/receiving/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/logistics/packaging": dynamic(() => import("@/app/(main)/COMPANY_30/logistics/packaging/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/logistics/info": dynamic(() => import("@/app/(main)/COMPANY_30/logistics/info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/logistics/inventory": dynamic(() => import("@/app/(main)/COMPANY_30/logistics/inventory/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/logistics/warehouse": dynamic(() => import("@/app/(main)/COMPANY_30/logistics/warehouse/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/outsourcing/subcontractor": dynamic(() => import("@/app/(main)/COMPANY_30/outsourcing/subcontractor/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/outsourcing/subcontractor-item": dynamic(() => import("@/app/(main)/COMPANY_30/outsourcing/subcontractor-item/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/purchase/order": dynamic(() => import("@/app/(main)/COMPANY_30/purchase/order/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/purchase/purchase-item": dynamic(() => import("@/app/(main)/COMPANY_30/purchase/purchase-item/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/purchase/supplier": dynamic(() => import("@/app/(main)/COMPANY_30/purchase/supplier/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/quality/inspection": dynamic(() => import("@/app/(main)/COMPANY_30/quality/inspection/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/quality/item-inspection": dynamic(() => import("@/app/(main)/COMPANY_30/quality/item-inspection/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/mold/info": dynamic(() => import("@/app/(main)/COMPANY_30/mold/info/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/design/project": dynamic(() => import("@/app/(main)/COMPANY_30/design/project/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/design/change-management": dynamic(() => import("@/app/(main)/COMPANY_30/design/change-management/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/design/my-work": dynamic(() => import("@/app/(main)/COMPANY_30/design/my-work/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/design/design-request": dynamic(() => import("@/app/(main)/COMPANY_30/design/design-request/page"), { ssr: false, loading: LoadingFallback }),
"/COMPANY_30/design/task-management": dynamic(() => import("@/app/(main)/COMPANY_30/design/task-management/page"), { ssr: false, loading: LoadingFallback }),
// === COMPANY_29 ===
"/COMPANY_29/master-data/item-info": dynamic(() => import("@/app/(main)/COMPANY_29/master-data/item-info/page"), { ssr: false, loading: LoadingFallback }),
@@ -262,6 +462,8 @@ const DYNAMIC_ADMIN_IMPORTS: Record<string, () => Promise<any>> = {
// COMPANY_7 (탑씰)
"/COMPANY_7/master-data/item-info": () => import("@/app/(main)/COMPANY_7/master-data/item-info/page"),
"/COMPANY_7/master-data/department": () => import("@/app/(main)/COMPANY_7/master-data/department/page"),
"/COMPANY_7/master-data/company": () => import("@/app/(main)/COMPANY_7/master-data/company/page"),
"/COMPANY_7/master-data/options": () => import("@/app/(main)/COMPANY_7/master-data/options/page"),
"/COMPANY_7/sales/order": () => import("@/app/(main)/COMPANY_7/sales/order/page"),
"/COMPANY_7/sales/customer": () => import("@/app/(main)/COMPANY_7/sales/customer/page"),
"/COMPANY_7/sales/sales-item": () => import("@/app/(main)/COMPANY_7/sales/sales-item/page"),
@@ -271,11 +473,16 @@ const DYNAMIC_ADMIN_IMPORTS: Record<string, () => Promise<any>> = {
"/COMPANY_7/production/process-info": () => import("@/app/(main)/COMPANY_7/production/process-info/page"),
"/COMPANY_7/production/work-instruction": () => import("@/app/(main)/COMPANY_7/production/work-instruction/page"),
"/COMPANY_7/production/plan-management": () => import("@/app/(main)/COMPANY_7/production/plan-management/page"),
"/COMPANY_7/production/bom": () => import("@/app/(main)/COMPANY_7/production/bom/page"),
"/COMPANY_7/equipment/info": () => import("@/app/(main)/COMPANY_7/equipment/info/page"),
"/COMPANY_7/equipment/plc-settings": () => import("@/app/(main)/COMPANY_7/equipment/plc-settings/page"),
"/COMPANY_7/logistics/material-status": () => import("@/app/(main)/COMPANY_7/logistics/material-status/page"),
"/COMPANY_7/logistics/outbound": () => import("@/app/(main)/COMPANY_7/logistics/outbound/page"),
"/COMPANY_7/logistics/receiving": () => import("@/app/(main)/COMPANY_7/logistics/receiving/page"),
"/COMPANY_7/logistics/packaging": () => import("@/app/(main)/COMPANY_7/logistics/packaging/page"),
"/COMPANY_7/logistics/info": () => import("@/app/(main)/COMPANY_7/logistics/info/page"),
"/COMPANY_7/logistics/inventory": () => import("@/app/(main)/COMPANY_7/logistics/inventory/page"),
"/COMPANY_7/logistics/warehouse": () => import("@/app/(main)/COMPANY_7/logistics/warehouse/page"),
"/COMPANY_7/outsourcing/subcontractor": () => import("@/app/(main)/COMPANY_7/outsourcing/subcontractor/page"),
"/COMPANY_7/outsourcing/subcontractor-item": () => import("@/app/(main)/COMPANY_7/outsourcing/subcontractor-item/page"),
"/COMPANY_7/design/project": () => import("@/app/(main)/COMPANY_7/design/project/page"),
@@ -308,7 +515,87 @@ const DYNAMIC_ADMIN_IMPORTS: Record<string, () => Promise<any>> = {
"/COMPANY_10/design/design-request": () => import("@/app/(main)/COMPANY_10/design/design-request/page"),
"/COMPANY_10/design/task-management": () => import("@/app/(main)/COMPANY_10/design/task-management/page"),
// COMPANY_9 (제일그라스)
"/COMPANY_9/master-data/item-info": () => import("@/app/(main)/COMPANY_9/master-data/item-info/page"),
"/COMPANY_9/master-data/department": () => import("@/app/(main)/COMPANY_9/master-data/department/page"),
"/COMPANY_9/master-data/company": () => import("@/app/(main)/COMPANY_9/master-data/company/page"),
"/COMPANY_9/master-data/options": () => import("@/app/(main)/COMPANY_9/master-data/options/page"),
"/COMPANY_9/sales/order": () => import("@/app/(main)/COMPANY_9/sales/order/page"),
"/COMPANY_9/sales/customer": () => import("@/app/(main)/COMPANY_9/sales/customer/page"),
"/COMPANY_9/sales/sales-item": () => import("@/app/(main)/COMPANY_9/sales/sales-item/page"),
"/COMPANY_9/sales/shipping-order": () => import("@/app/(main)/COMPANY_9/sales/shipping-order/page"),
"/COMPANY_9/sales/shipping-plan": () => import("@/app/(main)/COMPANY_9/sales/shipping-plan/page"),
"/COMPANY_9/sales/claim": () => import("@/app/(main)/COMPANY_9/sales/claim/page"),
"/COMPANY_9/sales/quote": () => import("@/app/(main)/COMPANY_9/sales/quote/page"),
"/COMPANY_9/production/process-info": () => import("@/app/(main)/COMPANY_9/production/process-info/page"),
"/COMPANY_9/production/work-instruction": () => import("@/app/(main)/COMPANY_9/production/work-instruction/page"),
"/COMPANY_9/production/plan-management": () => import("@/app/(main)/COMPANY_9/production/plan-management/page"),
"/COMPANY_9/production/bom": () => import("@/app/(main)/COMPANY_9/production/bom/page"),
"/COMPANY_9/equipment/info": () => import("@/app/(main)/COMPANY_9/equipment/info/page"),
"/COMPANY_9/equipment/plc-settings": () => import("@/app/(main)/COMPANY_9/equipment/plc-settings/page"),
"/COMPANY_9/monitoring/production": () => import("@/app/(main)/COMPANY_9/monitoring/production/page"),
"/COMPANY_9/monitoring/equipment": () => import("@/app/(main)/COMPANY_9/monitoring/equipment/page"),
"/COMPANY_9/monitoring/quality": () => import("@/app/(main)/COMPANY_9/monitoring/quality/page"),
"/COMPANY_9/logistics/material-status": () => import("@/app/(main)/COMPANY_9/logistics/material-status/page"),
"/COMPANY_9/logistics/outbound": () => import("@/app/(main)/COMPANY_9/logistics/outbound/page"),
"/COMPANY_9/logistics/receiving": () => import("@/app/(main)/COMPANY_9/logistics/receiving/page"),
"/COMPANY_9/logistics/packaging": () => import("@/app/(main)/COMPANY_9/logistics/packaging/page"),
"/COMPANY_9/logistics/info": () => import("@/app/(main)/COMPANY_9/logistics/info/page"),
"/COMPANY_9/logistics/inventory": () => import("@/app/(main)/COMPANY_9/logistics/inventory/page"),
"/COMPANY_9/logistics/warehouse": () => import("@/app/(main)/COMPANY_9/logistics/warehouse/page"),
"/COMPANY_9/outsourcing/subcontractor": () => import("@/app/(main)/COMPANY_9/outsourcing/subcontractor/page"),
"/COMPANY_9/outsourcing/subcontractor-item": () => import("@/app/(main)/COMPANY_9/outsourcing/subcontractor-item/page"),
"/COMPANY_9/purchase/order": () => import("@/app/(main)/COMPANY_9/purchase/order/page"),
"/COMPANY_9/purchase/purchase-item": () => import("@/app/(main)/COMPANY_9/purchase/purchase-item/page"),
"/COMPANY_9/purchase/supplier": () => import("@/app/(main)/COMPANY_9/purchase/supplier/page"),
"/COMPANY_9/quality/inspection": () => import("@/app/(main)/COMPANY_9/quality/inspection/page"),
"/COMPANY_9/quality/item-inspection": () => import("@/app/(main)/COMPANY_9/quality/item-inspection/page"),
"/COMPANY_9/mold/info": () => import("@/app/(main)/COMPANY_9/mold/info/page"),
"/COMPANY_9/design/project": () => import("@/app/(main)/COMPANY_9/design/project/page"),
"/COMPANY_9/design/change-management": () => import("@/app/(main)/COMPANY_9/design/change-management/page"),
"/COMPANY_9/design/my-work": () => import("@/app/(main)/COMPANY_9/design/my-work/page"),
"/COMPANY_9/design/design-request": () => import("@/app/(main)/COMPANY_9/design/design-request/page"),
"/COMPANY_9/design/task-management": () => import("@/app/(main)/COMPANY_9/design/task-management/page"),
// COMPANY_30
"/COMPANY_30/master-data/item-info": () => import("@/app/(main)/COMPANY_30/master-data/item-info/page"),
"/COMPANY_30/master-data/department": () => import("@/app/(main)/COMPANY_30/master-data/department/page"),
"/COMPANY_30/master-data/company": () => import("@/app/(main)/COMPANY_30/master-data/company/page"),
"/COMPANY_30/master-data/options": () => import("@/app/(main)/COMPANY_30/master-data/options/page"),
"/COMPANY_30/sales/order": () => import("@/app/(main)/COMPANY_30/sales/order/page"),
"/COMPANY_30/sales/customer": () => import("@/app/(main)/COMPANY_30/sales/customer/page"),
"/COMPANY_30/sales/sales-item": () => import("@/app/(main)/COMPANY_30/sales/sales-item/page"),
"/COMPANY_30/sales/shipping-order": () => import("@/app/(main)/COMPANY_30/sales/shipping-order/page"),
"/COMPANY_30/sales/shipping-plan": () => import("@/app/(main)/COMPANY_30/sales/shipping-plan/page"),
"/COMPANY_30/sales/claim": () => import("@/app/(main)/COMPANY_30/sales/claim/page"),
"/COMPANY_30/sales/quote": () => import("@/app/(main)/COMPANY_30/sales/quote/page"),
"/COMPANY_30/production/process-info": () => import("@/app/(main)/COMPANY_30/production/process-info/page"),
"/COMPANY_30/production/work-instruction": () => import("@/app/(main)/COMPANY_30/production/work-instruction/page"),
"/COMPANY_30/production/plan-management": () => import("@/app/(main)/COMPANY_30/production/plan-management/page"),
"/COMPANY_30/production/bom": () => import("@/app/(main)/COMPANY_30/production/bom/page"),
"/COMPANY_30/equipment/info": () => import("@/app/(main)/COMPANY_30/equipment/info/page"),
"/COMPANY_30/equipment/plc-settings": () => import("@/app/(main)/COMPANY_30/equipment/plc-settings/page"),
"/COMPANY_30/monitoring/production": () => import("@/app/(main)/COMPANY_30/monitoring/production/page"),
"/COMPANY_30/monitoring/equipment": () => import("@/app/(main)/COMPANY_30/monitoring/equipment/page"),
"/COMPANY_30/monitoring/quality": () => import("@/app/(main)/COMPANY_30/monitoring/quality/page"),
"/COMPANY_30/logistics/material-status": () => import("@/app/(main)/COMPANY_30/logistics/material-status/page"),
"/COMPANY_30/logistics/outbound": () => import("@/app/(main)/COMPANY_30/logistics/outbound/page"),
"/COMPANY_30/logistics/receiving": () => import("@/app/(main)/COMPANY_30/logistics/receiving/page"),
"/COMPANY_30/logistics/packaging": () => import("@/app/(main)/COMPANY_30/logistics/packaging/page"),
"/COMPANY_30/logistics/info": () => import("@/app/(main)/COMPANY_30/logistics/info/page"),
"/COMPANY_30/logistics/inventory": () => import("@/app/(main)/COMPANY_30/logistics/inventory/page"),
"/COMPANY_30/logistics/warehouse": () => import("@/app/(main)/COMPANY_30/logistics/warehouse/page"),
"/COMPANY_30/outsourcing/subcontractor": () => import("@/app/(main)/COMPANY_30/outsourcing/subcontractor/page"),
"/COMPANY_30/outsourcing/subcontractor-item": () => import("@/app/(main)/COMPANY_30/outsourcing/subcontractor-item/page"),
"/COMPANY_30/purchase/order": () => import("@/app/(main)/COMPANY_30/purchase/order/page"),
"/COMPANY_30/purchase/purchase-item": () => import("@/app/(main)/COMPANY_30/purchase/purchase-item/page"),
"/COMPANY_30/purchase/supplier": () => import("@/app/(main)/COMPANY_30/purchase/supplier/page"),
"/COMPANY_30/quality/inspection": () => import("@/app/(main)/COMPANY_30/quality/inspection/page"),
"/COMPANY_30/quality/item-inspection": () => import("@/app/(main)/COMPANY_30/quality/item-inspection/page"),
"/COMPANY_30/mold/info": () => import("@/app/(main)/COMPANY_30/mold/info/page"),
"/COMPANY_30/design/project": () => import("@/app/(main)/COMPANY_30/design/project/page"),
"/COMPANY_30/design/change-management": () => import("@/app/(main)/COMPANY_30/design/change-management/page"),
"/COMPANY_30/design/my-work": () => import("@/app/(main)/COMPANY_30/design/my-work/page"),
"/COMPANY_30/design/design-request": () => import("@/app/(main)/COMPANY_30/design/design-request/page"),
"/COMPANY_30/design/task-management": () => import("@/app/(main)/COMPANY_30/design/task-management/page"),
// COMPANY_29
"/COMPANY_29/master-data/item-info": () => import("@/app/(main)/COMPANY_29/master-data/item-info/page"),
"/COMPANY_29/master-data/department": () => import("@/app/(main)/COMPANY_29/master-data/department/page"),
@@ -480,6 +767,7 @@ const COMPANY_PAGE_PREFIXES = [
"/purchase/",
"/quality/",
"/mold/",
"/monitoring/",
];
function isCompanyPage(url: string): boolean {
+37 -9
View File
@@ -109,11 +109,14 @@ const convertMenuToUI = (menus: MenuItem[], userInfo: ExtendedUserInfo | null, p
.filter((menu) => (menu.parent_obj_id || menu.PARENT_OBJ_ID) === parentId)
.filter((menu) => (menu.status || menu.STATUS) === "active")
.filter((menu) => {
// 회사관리 메뉴는 최고관리자만 표시
// 최고관리자 전용 메뉴 필터링
const url = (menu.menu_url || menu.MENU_URL || "").toLowerCase();
if (url.includes("companylist") || url.includes("company-list")) {
return isSuperAdmin;
}
if (url.includes("smart-factory-log")) {
return isSuperAdmin;
}
return true;
})
.sort((a, b) => (a.seq || a.SEQ || 0) - (b.seq || b.SEQ || 0));
@@ -260,6 +263,7 @@ function AppLayoutInner({ children }: AppLayoutProps) {
});
const [collapsedHover, setCollapsedHover] = useState(false);
const collapsedHoverTimer = useRef<NodeJS.Timeout | null>(null);
const [hasPopMenus, setHasPopMenus] = useState(false);
const toggleSidebarCollapse = () => {
setSidebarCollapsed((prev) => {
@@ -344,6 +348,26 @@ function AppLayoutInner({ children }: AppLayoutProps) {
return () => window.removeEventListener("resize", checkIsMobile);
}, []);
// POP 메뉴 존재 여부 확인
useEffect(() => {
const checkPopMenus = async () => {
try {
const response = await menuApi.getPopMenus();
if (response.success && response.data) {
const { childMenus, landingMenu } = response.data;
setHasPopMenus(!!(landingMenu?.menu_url || childMenus.length > 0));
} else {
setHasPopMenus(false);
}
} catch {
setHasPopMenus(false);
}
};
if (user) {
checkPopMenus();
}
}, [user]);
// 프로필 관련 로직
const {
isModalOpen,
@@ -718,10 +742,12 @@ function AppLayoutInner({ children }: AppLayoutProps) {
<FileCheck className="mr-2 h-4 w-4" />
<span></span>
</DropdownMenuItem>
<DropdownMenuItem onClick={handlePopModeClick}>
<Monitor className="mr-2 h-4 w-4" />
<span>POP </span>
</DropdownMenuItem>
{hasPopMenus && (
<DropdownMenuItem onClick={handlePopModeClick}>
<Monitor className="mr-2 h-4 w-4" />
<span>POP </span>
</DropdownMenuItem>
)}
<DropdownMenuSeparator />
<div className="px-1 py-0.5">
<ThemeToggle />
@@ -978,10 +1004,12 @@ function AppLayoutInner({ children }: AppLayoutProps) {
<FileCheck className="mr-2 h-4 w-4" />
<span></span>
</DropdownMenuItem>
<DropdownMenuItem onClick={handlePopModeClick}>
<Monitor className="mr-2 h-4 w-4" />
<span>POP </span>
</DropdownMenuItem>
{hasPopMenus && (
<DropdownMenuItem onClick={handlePopModeClick}>
<Monitor className="mr-2 h-4 w-4" />
<span>POP </span>
</DropdownMenuItem>
)}
<DropdownMenuSeparator />
<DropdownMenuItem onClick={handleLogout}>
<LogOut className="mr-2 h-4 w-4" />
+21 -24
View File
@@ -2,6 +2,8 @@
import React, { useState, useEffect, useRef, ReactNode } from "react";
import { useRouter } from "next/navigation";
import { useAuth } from "@/hooks/useAuth";
import { usePopSettings } from "@/hooks/pop/usePopSettings";
interface PopShellProps {
children: ReactNode;
@@ -13,6 +15,10 @@ interface PopShellProps {
export function PopShell({ children, showBanner = true, title, showBack = false, headerRight }: PopShellProps) {
const router = useRouter();
const { user, logout } = useAuth();
const displayName = user?.userName || user?.userId || "사용자";
const deptName = user?.deptName || "";
const initial = displayName.charAt(0);
const [mounted, setMounted] = useState(false);
const [hours, setHours] = useState("00");
const [minutes, setMinutes] = useState("00");
@@ -90,14 +96,15 @@ export function PopShell({ children, showBanner = true, title, showBack = false,
const handleLogout = () => {
setProfileOpen(false);
localStorage.removeItem("token");
localStorage.removeItem("accessToken");
localStorage.removeItem("refreshToken");
window.location.href = "/login";
logout();
};
const marqueeText =
"[공지] 금일 오후 3시 전체 안전교육 실시 예정입니다. 전 직원 필참 바랍니다. \u00a0\u00a0|\u00a0\u00a0 [알림] 내일 설비 정기점검으로 인한 3호기 가동 중지 예정 \u00a0\u00a0|\u00a0\u00a0 [안내] 4월 생산실적 우수팀 발표 - 생산1팀 축하드립니다!";
// POP 설정에서 배너 텍스트 로드 (POP화면설정에서 관리)
const { settings: popSettings } = usePopSettings("/pop/home");
const homeConfig = (popSettings as any)?.screens?.home;
const bannerEnabled = homeConfig?.bannerEnabled ?? true;
const bannerText = homeConfig?.bannerText;
const marqueeText = bannerText || "[공지] 금일 오후 3시 전체 안전교육 실시 예정입니다. 전 직원 필참 바랍니다. \u00a0\u00a0|\u00a0\u00a0 [알림] 내일 설비 정기점검으로 인한 3호기 가동 중지 예정 \u00a0\u00a0|\u00a0\u00a0 [안내] 4월 생산실적 우수팀 발표 - 생산1팀 축하드립니다!";
return (
<div className="min-h-screen min-h-dvh flex flex-col" style={{ background: "#F5F5F5" }}>
@@ -148,7 +155,7 @@ export function PopShell({ children, showBanner = true, title, showBack = false,
) : (
<>
<span className="text-white text-lg font-bold tracking-tight leading-tight truncate">
{user?.companyName || "POP"}
</span>
<span className="text-white/50 text-xs font-medium leading-tight">
@@ -224,14 +231,14 @@ export function PopShell({ children, showBanner = true, title, showBack = false,
className="flex items-center gap-2.5 cursor-pointer"
>
<div className="hidden sm:flex flex-col items-end">
<span className="text-sm text-white/90 font-semibold leading-tight"></span>
<span className="text-xs text-white/40 font-medium leading-tight">1</span>
<span className="text-sm text-white/90 font-semibold leading-tight">{displayName}</span>
<span className="text-xs text-white/40 font-medium leading-tight">{deptName}</span>
</div>
<div
className="w-10 h-10 rounded-full bg-blue-500 flex items-center justify-center text-sm font-bold text-white shrink-0 transition-transform active:scale-95"
style={{ boxShadow: "0 2px 8px rgba(59,130,246,.35)" }}
>
{initial}
</div>
</button>
@@ -245,8 +252,8 @@ export function PopShell({ children, showBanner = true, title, showBack = false,
>
{/* User Info */}
<div className="px-4 py-3 border-b border-gray-100">
<p className="text-sm font-semibold text-gray-900"></p>
<p className="text-xs text-gray-400 mt-0.5">1</p>
<p className="text-sm font-semibold text-gray-900">{displayName}</p>
<p className="text-xs text-gray-400 mt-0.5">{deptName || user?.userId}</p>
</div>
{/* Menu Items */}
@@ -294,7 +301,7 @@ export function PopShell({ children, showBanner = true, title, showBack = false,
</header>
{/* ===== NOTICE BANNER (Marquee) ===== */}
{showBanner && <div className="bg-amber-50 border-b border-amber-200 px-4 py-2 flex items-center gap-3">
{showBanner && bannerEnabled && <div className="bg-amber-50 border-b border-amber-200 px-4 py-2 flex items-center gap-3">
<div className="flex items-center gap-1.5 shrink-0">
<span className="text-amber-600 text-sm">📢</span>
<span className="text-xs font-bold text-amber-700"></span>
@@ -316,17 +323,7 @@ export function PopShell({ children, showBanner = true, title, showBack = false,
{children}
</main>
{/* ===== FOOTER ===== */}
<footer className="border-t border-gray-200 bg-white px-4 sm:px-6 lg:px-8 py-3 sm:py-4">
<div className="max-w-[1400px] mx-auto flex flex-col sm:flex-row items-center justify-between gap-2 text-xs text-gray-400">
<span>&copy; 2026 . All rights reserved.</span>
<div className="flex items-center gap-3 sm:gap-4">
<span>Version 1.0.0</span>
<span className="hidden sm:inline">|</span>
<span>긴급연락: 042-XXX-XXXX</span>
</div>
</div>
</footer>
{/* FOOTER 삭제 — POP 화면에서 불필요 */}
{/* Marquee keyframes */}
<style jsx global>{`
@@ -145,9 +145,9 @@ export function RecentActivity() {
</div>
) : (
<div className="flex flex-col gap-2 sm:gap-3">
{activities.map((item) => (
{activities.map((item, idx) => (
<div
key={item.id}
key={`${item.id}-${idx}`}
className="flex items-center gap-3 sm:gap-4 p-3 rounded-xl transition-all duration-150 hover:bg-gray-50 hover:translate-x-1"
>
<span
@@ -36,18 +36,22 @@ export const BarcodeScanModal: React.FC<BarcodeScanModalProps> = ({
}) => {
const [isScanning, setIsScanning] = useState(false);
const [scannedCode, setScannedCode] = useState<string>("");
const [manualInput, setManualInput] = useState<string>("");
const [error, setError] = useState<string>("");
const [hasPermission, setHasPermission] = useState<boolean | null>(null);
const webcamRef = useRef<Webcam>(null);
const codeReaderRef = useRef<BrowserMultiFormatReader | null>(null);
const scanIntervalRef = useRef<NodeJS.Timeout | null>(null);
const manualInputRef = useRef<HTMLInputElement>(null);
// 바코드 리더 초기화 + 모달 열릴 때 상태 리셋
useEffect(() => {
if (open) {
setScannedCode("");
setManualInput("");
setError("");
setIsScanning(false);
setHasPermission(null);
codeReaderRef.current = new BrowserMultiFormatReader();
}
@@ -73,10 +77,15 @@ export const BarcodeScanModal: React.FC<BarcodeScanModalProps> = ({
}
try {
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
// 후면 카메라 먼저 시도, 실패하면 전면 카메라 fallback
let stream: MediaStream;
try {
stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: "environment" } });
} catch {
stream = await navigator.mediaDevices.getUserMedia({ video: true });
}
setHasPermission(true);
stream.getTracks().forEach((track) => track.stop());
toast.success("카메라 권한이 허용되었습니다.");
} catch (err: any) {
setHasPermission(false);
@@ -154,12 +163,14 @@ export const BarcodeScanModal: React.FC<BarcodeScanModalProps> = ({
}
};
// 수동 확인 버튼
// 수동 확인 버튼 (스캔 결과 또는 직접 입력)
const handleConfirm = () => {
if (scannedCode) {
onScanSuccess(scannedCode);
const code = scannedCode || manualInput.trim();
if (code) {
onScanSuccess(code); // 호출 측에서 검색 필드를 덮어쓰기
onOpenChange(false);
} else {
toast.error("스캔된 바코드가 없습니다.");
toast.error("바코드를 스캔하거나 직접 입력해주세요.");
}
};
@@ -254,7 +265,10 @@ export const BarcodeScanModal: React.FC<BarcodeScanModalProps> = ({
audio={false}
screenshotFormat="image/jpeg"
videoConstraints={{
facingMode: "environment",
facingMode: { ideal: "environment" },
}}
onUserMediaError={() => {
// environment 카메라 실패 시 자동 fallback (Webcam 내부 처리)
}}
className="h-full w-full object-cover"
/>
@@ -285,6 +299,41 @@ export const BarcodeScanModal: React.FC<BarcodeScanModalProps> = ({
</div>
)}
{/* 수동 입력 (카메라 사용 불가 시 또는 외장 스캐너 사용 시) */}
<div className="rounded-md border border-border bg-muted/30 p-3 space-y-2">
<p className="text-xs font-medium text-muted-foreground"> </p>
<div className="flex gap-2">
<input
ref={manualInputRef}
type="text"
value={manualInput}
onChange={(e) => setManualInput(e.target.value)}
onKeyDown={(e) => {
if (e.key === "Enter" && manualInput.trim()) {
e.preventDefault();
onScanSuccess(manualInput.trim());
onOpenChange(false);
}
}}
placeholder="바코드/QR 번호 입력 후 Enter"
className="flex-1 h-11 rounded-lg border border-border px-3 text-sm focus:outline-none focus:ring-2 focus:ring-primary"
autoFocus={hasPermission === false}
/>
<Button
onClick={() => {
if (manualInput.trim()) {
onScanSuccess(manualInput.trim());
onOpenChange(false);
}
}}
disabled={!manualInput.trim()}
className="h-11 px-4"
>
</Button>
</div>
</div>
{/* 바코드 포맷 정보 */}
<div className="rounded-md border border-border bg-muted/50 p-3">
<div className="flex items-start gap-2">
@@ -310,9 +310,15 @@ export function InboundCartPage() {
try {
// 확정 시점에 채번 (동시접속 충돌 방지)
// POP 화면설정에서 선택한 채번규칙 사용 (없으면 기본)
let finalNumber = "";
try {
const numRes = await apiClient.get("/receiving/generate-number");
const settingsRes: any = await apiClient.get("/screen-management/screens/6527/layout-pop").catch(() => null);
const ruleId = settingsRes?.data?.data?.settings?.popConfig?.inbound?.numberingRuleId;
const url = ruleId && ruleId !== "__none__"
? `/receiving/generate-number?ruleId=${encodeURIComponent(ruleId)}`
: "/receiving/generate-number";
const numRes = await apiClient.get(url);
if (numRes.data?.success && numRes.data?.data) {
finalNumber = numRes.data.data;
setInboundNumber(finalNumber);
@@ -344,6 +350,7 @@ export function InboundCartPage() {
reference_number: item.purchase_no,
supplier_code: item.supplier_code,
supplier_name: item.supplier_name,
inbound_status: "입고완료",
inspection_status: inspResult?.completed
? "검사완료"
: item.inspection_required
@@ -305,9 +305,16 @@ export function OutboundCartPage() {
try {
// Generate outbound number at confirm time
// POP 화면설정에서 선택한 채번규칙 사용 (없으면 기본)
// 출고 장바구니 전용 screen_id 7010
let finalNumber = "";
try {
const numRes = await apiClient.get("/outbound/generate-number");
const settingsRes: any = await apiClient.get("/screen-management/screens/7010/layout-pop").catch(() => null);
const ruleId = settingsRes?.data?.data?.settings?.popConfig?.outbound?.numberingRuleId;
const url = ruleId && ruleId !== "__none__"
? `/outbound/generate-number?ruleId=${encodeURIComponent(ruleId)}`
: "/outbound/generate-number";
const numRes = await apiClient.get(url);
if (numRes.data?.success && numRes.data?.data) {
finalNumber = numRes.data.data;
setOutboundNumber(finalNumber);
@@ -337,7 +344,7 @@ export function OutboundCartPage() {
customer_name: item.customer_name,
source_type: "shipment_instruction_detail",
source_id: item.source_id || item.id,
outbound_status: "대기",
outbound_status: "출고완료",
})),
};
@@ -43,27 +43,89 @@ function QtyInput({
onChange: (v: number) => void;
max: number;
}) {
const [padOpen, setPadOpen] = useState(false);
const [padValue, setPadValue] = useState(String(value));
const handlePadOpen = () => {
setPadValue("");
setPadOpen(true);
};
const handlePadKey = (key: string) => {
if (key === "backspace") {
setPadValue((prev) => prev.length > 1 ? prev.slice(0, -1) : "0");
} else if (key === "clear") {
setPadValue("0");
} else if (key === "max") {
setPadValue(String(max));
} else {
setPadValue((prev) => prev === "0" ? key : prev + key);
}
};
const handlePadConfirm = () => {
const num = Math.min(Math.max(0, parseInt(padValue, 10) || 0), max);
onChange(num);
setPadOpen(false);
};
return (
<div className="flex items-center gap-2">
<button
onClick={() => onChange(Math.max(0, value - 1))}
className="w-10 h-10 rounded-lg bg-gray-100 text-gray-600 text-lg font-bold flex items-center justify-center active:scale-95 transition-all hover:bg-gray-200"
>
-
</button>
<span
className="w-12 text-center text-lg font-bold text-gray-900"
style={{ fontVariantNumeric: "tabular-nums" }}
>
{value}
</span>
<button
onClick={() => onChange(Math.min(max, value + 1))}
className="w-10 h-10 rounded-lg bg-gray-100 text-gray-600 text-lg font-bold flex items-center justify-center active:scale-95 transition-all hover:bg-gray-200"
>
+
</button>
</div>
<>
<div className="flex items-center gap-2">
<button
onClick={() => onChange(Math.max(0, value - 1))}
className="w-10 h-10 rounded-lg bg-gray-100 text-gray-600 text-lg font-bold flex items-center justify-center active:scale-95 transition-all hover:bg-gray-200"
>
-
</button>
<button
onClick={handlePadOpen}
className="w-16 h-10 text-center text-lg font-bold text-gray-900 bg-gray-50 rounded-lg border-2 border-gray-200 hover:border-red-300 active:scale-95 transition-all"
style={{ fontVariantNumeric: "tabular-nums" }}
>
{value}
</button>
<button
onClick={() => onChange(Math.min(max, value + 1))}
className="w-10 h-10 rounded-lg bg-gray-100 text-gray-600 text-lg font-bold flex items-center justify-center active:scale-95 transition-all hover:bg-gray-200"
>
+
</button>
</div>
{/* 숫자 키패드 모달 */}
{padOpen && (
<div className="fixed inset-0 z-[60] flex items-center justify-center">
<div className="absolute inset-0 bg-black/40" onClick={() => setPadOpen(false)} />
<div className="relative bg-white rounded-2xl shadow-2xl p-4 w-[280px] z-10">
<div className="text-center mb-3">
<p className="text-sm text-gray-500"> ( {max})</p>
<p className="text-3xl font-bold text-gray-900 mt-1" style={{ fontVariantNumeric: "tabular-nums" }}>{padValue || "0"}</p>
</div>
<div className="grid grid-cols-3 gap-2 mb-3">
{["1","2","3","4","5","6","7","8","9"].map((k) => (
<button key={k} onClick={() => handlePadKey(k)}
className="h-12 rounded-xl bg-gray-100 text-lg font-bold text-gray-800 active:scale-95 active:bg-gray-200 transition-all">{k}</button>
))}
<button onClick={() => handlePadKey("clear")}
className="h-12 rounded-xl bg-gray-200 text-sm font-bold text-gray-600 active:scale-95 transition-all">C</button>
<button onClick={() => handlePadKey("0")}
className="h-12 rounded-xl bg-gray-100 text-lg font-bold text-gray-800 active:scale-95 transition-all">0</button>
<button onClick={() => handlePadKey("backspace")}
className="h-12 rounded-xl bg-gray-200 text-sm font-bold text-gray-600 active:scale-95 transition-all"></button>
</div>
<button onClick={() => handlePadKey("max")}
className="w-full h-10 rounded-xl bg-red-50 text-red-600 text-sm font-bold mb-2 active:scale-95 transition-all">MAX ({max})</button>
<div className="flex gap-2">
<button onClick={() => setPadOpen(false)}
className="flex-1 h-11 rounded-xl bg-gray-100 text-gray-700 font-semibold active:scale-95 transition-all"></button>
<button onClick={handlePadConfirm}
className="flex-1 h-11 rounded-xl bg-red-500 text-white font-bold active:scale-95 transition-all"></button>
</div>
</div>
</div>
)}
</>
);
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff