diff --git a/src/components/production/WorkOrders/actions.ts b/src/components/production/WorkOrders/actions.ts index 732e0606..418f99d2 100644 --- a/src/components/production/WorkOrders/actions.ts +++ b/src/components/production/WorkOrders/actions.ts @@ -773,6 +773,52 @@ export async function saveInspectionData( } } +// ===== 검사 설정 조회 (공정 판별 + 구성품 목록) ===== +export interface InspectionConfigGapPoint { + point: string; + design_value: string; +} + +export interface InspectionConfigItem { + id: string; + name: string; + gap_points: InspectionConfigGapPoint[]; +} + +export interface InspectionConfigData { + work_order_id: number; + process_type: string; + product_code: string | null; + template_id: number | null; + items: InspectionConfigItem[]; +} + +export async function getInspectionConfig( + workOrderId: string | number +): Promise<{ success: boolean; data?: InspectionConfigData; error?: string }> { + try { + const { response, error } = await serverFetch( + buildApiUrl(`/api/v1/work-orders/${workOrderId}/inspection-config`), + { method: 'GET' } + ); + + if (error || !response) { + return { success: false, error: error?.message || 'API 요청 실패' }; + } + + const result = await response.json(); + if (!response.ok || !result.success) { + return { success: false, error: result.message || '검사 설정을 불러올 수 없습니다.' }; + } + + return { success: true, data: result.data }; + } catch (error) { + if (isNextRedirectError(error)) throw error; + console.error('[WorkOrderActions] getInspectionConfig error:', error); + return { success: false, error: '서버 오류가 발생했습니다.' }; + } +} + // ===== 검사 문서 템플릿 조회 (document_template 기반) ===== import type { InspectionTemplateData } from '@/components/production/WorkerScreen/types'; diff --git a/src/components/production/WorkOrders/documents/TemplateInspectionContent.tsx b/src/components/production/WorkOrders/documents/TemplateInspectionContent.tsx index 91455ec7..21f1e05d 100644 --- a/src/components/production/WorkOrders/documents/TemplateInspectionContent.tsx +++ b/src/components/production/WorkOrders/documents/TemplateInspectionContent.tsx @@ -36,6 +36,8 @@ import { } from './inspection-shared'; import { formatNumber } from '@/lib/utils/amount'; import type { BendingInfoExtended } from './bending/types'; +import { getInspectionConfig } from '../actions'; +import type { InspectionConfigData } from '../actions'; export type { InspectionContentRef }; @@ -375,10 +377,60 @@ export const TemplateInspectionContent = forwardRef(null); + + useEffect(() => { + if (!isBending || !order.id) return; + let cancelled = false; + getInspectionConfig(order.id).then(result => { + if (!cancelled && result.success && result.data) { + setInspectionConfig(result.data); + } + }); + return () => { cancelled = true; }; + }, [isBending, order.id]); + const bendingProducts = useMemo(() => { if (!isBending) return []; + + // API 응답이 있고 items가 있으면 API 기반 구성품 사용 + if (inspectionConfig?.items?.length) { + const productCode = inspectionConfig.product_code || ''; + // bending_info에서 dimension 보조 데이터 추출 + const bi = order.bendingInfo as BendingInfoExtended | undefined; + const wallLen = bi?.guideRail?.wall?.lengthData?.[0]?.length; + const sideLen = bi?.guideRail?.side?.lengthData?.[0]?.length; + + return inspectionConfig.items.map((item): BendingProduct => { + // API id → 표시용 매핑 (이름, 타입, 치수) + const displayMap: Record = { + guide_rail_wall: { name: '가이드레일', type: '벽면형', len: String(wallLen || 3500), wid: 'N/A' }, + guide_rail_side: { name: '가이드레일', type: '측면형', len: String(sideLen || 3000), wid: 'N/A' }, + bottom_bar: { name: '하단마감재', type: '60×40', len: '3000', wid: 'N/A' }, + case_box: { name: '케이스', type: '양면', len: '3000', wid: 'N/A' }, + smoke_w50: { name: '연기차단재', type: '화이바 W50\n가이드레일용', len: '-', wid: '50' }, + smoke_w80: { name: '연기차단재', type: '화이바 W80\n케이스용', len: '-', wid: '80' }, + }; + const d = displayMap[item.id] || { name: item.name, type: '', len: '-', wid: 'N/A' }; + return { + id: item.id, + category: productCode, + productName: d.name, + productType: d.type, + lengthDesign: d.len, + widthDesign: d.wid, + gapPoints: item.gap_points.map(gp => ({ + point: gp.point, + designValue: gp.design_value, + })), + }; + }); + } + + // fallback: 기존 프론트 로직 사용 return buildBendingProducts(order); - }, [isBending, order]); + }, [isBending, order, inspectionConfig]); const bendingExpandedRows = useMemo(() => { if (!isBending) return [];