feat: [inspection] Phase 3 TemplateInspectionContent API 연동

- getInspectionConfig Server Action 추가
  - InspectionConfigData/Item/GapPoint 타입 정의
- TemplateInspectionContent API 연동
  - inspectionConfig state + useEffect로 API 호출
  - bendingProducts: API 우선 → buildBendingProducts fallback
  - bending_info에서 dimension 보조 데이터 추출
This commit is contained in:
2026-02-27 16:36:35 +09:00
parent 2c87ac535a
commit 0da6586bb6
2 changed files with 99 additions and 1 deletions

View File

@@ -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';

View File

@@ -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<InspectionContentRef, Templa
)?.id ?? null;
}, [isBending, template.columns]);
// ===== inspection-config API 연동 =====
const [inspectionConfig, setInspectionConfig] = useState<InspectionConfigData | null>(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<string, { name: string; type: string; len: string; wid: string }> = {
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 [];