diff --git a/backend-node/src/controllers/processInfoController.ts b/backend-node/src/controllers/processInfoController.ts index 5869b112..a8d99fb1 100644 --- a/backend-node/src/controllers/processInfoController.ts +++ b/backend-node/src/controllers/processInfoController.ts @@ -420,3 +420,44 @@ export async function saveRoutingDetails(req: AuthenticatedRequest, res: Respons return res.status(500).json({ success: false, message: error.message }); } } + +// ═══════════════════════════════════════════ +// BOM 구성 자재 조회 (품목코드 기반) +// ═══════════════════════════════════════════ + +export async function getBomMaterials(req: AuthenticatedRequest, res: Response) { + try { + const companyCode = req.user!.companyCode; + const { itemCode } = req.params; + + if (!itemCode) { + return res.status(400).json({ success: false, message: "itemCode는 필수입니다" }); + } + + const query = ` + SELECT + bd.id, + bd.child_item_id, + bd.quantity, + bd.unit as detail_unit, + bd.process_type, + i.item_name as child_item_name, + i.item_number as child_item_code, + i.type as child_item_type, + i.unit as item_unit + FROM bom b + JOIN bom_detail bd ON b.id = bd.bom_id AND b.company_code = bd.company_code + LEFT JOIN item_info i ON bd.child_item_id = i.id AND bd.company_code = i.company_code + WHERE b.item_code = $1 AND b.company_code = $2 + ORDER BY bd.seq_no ASC, bd.created_date ASC + `; + + const result = await pool.query(query, [itemCode, companyCode]); + + logger.info("BOM 자재 조회 성공", { companyCode, itemCode, count: result.rowCount }); + return res.json({ success: true, data: result.rows }); + } catch (error: any) { + logger.error("BOM 자재 조회 실패", { error: error.message }); + return res.status(500).json({ success: false, message: error.message }); + } +} diff --git a/backend-node/src/routes/processInfoRoutes.ts b/backend-node/src/routes/processInfoRoutes.ts index 30fb9479..3507707e 100644 --- a/backend-node/src/routes/processInfoRoutes.ts +++ b/backend-node/src/routes/processInfoRoutes.ts @@ -39,4 +39,7 @@ router.delete("/routing-versions/:id", ctrl.deleteRoutingVersion); router.get("/routing-details/:versionId", ctrl.getRoutingDetails); router.put("/routing-details/:versionId", ctrl.saveRoutingDetails); +// BOM 구성 자재 조회 +router.get("/bom-materials/:itemCode", ctrl.getBomMaterials); + export default router; diff --git a/frontend/lib/api/processInfo.ts b/frontend/lib/api/processInfo.ts index 4cc565e2..b52272a5 100644 --- a/frontend/lib/api/processInfo.ts +++ b/frontend/lib/api/processInfo.ts @@ -274,3 +274,26 @@ export async function saveRoutingDetails( return { success: false, message: e.message }; } } + +// ═══ BOM 구성 자재 조회 ═══ + +export interface BomMaterial { + id: string; + child_item_id: string; + quantity: string; + detail_unit: string | null; + process_type: string | null; + child_item_name: string | null; + child_item_code: string | null; + child_item_type: string | null; + item_unit: string | null; +} + +export async function getBomMaterials(itemCode: string): Promise> { + try { + const res = await apiClient.get(`${BASE}/bom-materials/${encodeURIComponent(itemCode)}`); + return res.data; + } catch (e: any) { + return { success: false, message: e.message }; + } +} diff --git a/frontend/lib/registry/components/v2-process-work-standard/ProcessWorkStandardComponent.tsx b/frontend/lib/registry/components/v2-process-work-standard/ProcessWorkStandardComponent.tsx index ad169acd..f5c7c794 100644 --- a/frontend/lib/registry/components/v2-process-work-standard/ProcessWorkStandardComponent.tsx +++ b/frontend/lib/registry/components/v2-process-work-standard/ProcessWorkStandardComponent.tsx @@ -208,6 +208,7 @@ export function ProcessWorkStandardComponent({ selectedWorkItemDetails={selectedDetailsByPhase[phase.key] || []} detailTypes={config.detailTypes} readonly={config.readonly} + selectedItemCode={selection.itemCode || undefined} onSelectWorkItem={handleSelectWorkItem} onAddWorkItem={handleAddWorkItem} onEditWorkItem={handleEditWorkItem} diff --git a/frontend/lib/registry/components/v2-process-work-standard/components/DetailFormModal.tsx b/frontend/lib/registry/components/v2-process-work-standard/components/DetailFormModal.tsx index ec22d200..eaeb7262 100644 --- a/frontend/lib/registry/components/v2-process-work-standard/components/DetailFormModal.tsx +++ b/frontend/lib/registry/components/v2-process-work-standard/components/DetailFormModal.tsx @@ -1,10 +1,11 @@ "use client"; -import React, { useState, useEffect } from "react"; -import { Search } from "lucide-react"; +import React, { useState, useEffect, useCallback } from "react"; +import { Search, Loader2 } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; +import { Checkbox } from "@/components/ui/checkbox"; import { Select, SelectContent, @@ -22,6 +23,7 @@ import { } from "@/components/ui/dialog"; import { WorkItemDetail, DetailTypeDefinition, InspectionStandard } from "../types"; import { InspectionStandardLookup } from "./InspectionStandardLookup"; +import { getBomMaterials, BomMaterial } from "@/lib/api/processInfo"; interface DetailFormModalProps { open: boolean; @@ -30,24 +32,53 @@ interface DetailFormModalProps { detailTypes: DetailTypeDefinition[]; editData?: WorkItemDetail | null; mode: "add" | "edit"; + selectedItemCode?: string; } -const LOOKUP_TARGETS = [ - { value: "equipment", label: "설비정보" }, - { value: "material", label: "자재정보" }, - { value: "worker", label: "작업자정보" }, - { value: "tool", label: "공구정보" }, - { value: "document", label: "문서정보" }, -]; - const INPUT_TYPES = [ { value: "text", label: "텍스트" }, { value: "number", label: "숫자" }, { value: "date", label: "날짜" }, - { value: "textarea", label: "장문텍스트" }, - { value: "select", label: "선택형" }, + { value: "textarea", label: "장문 텍스트" }, ]; +const UNIT_OPTIONS = [ + "mm", "cm", "m", "μm", "℃", "℉", "bar", "Pa", "MPa", "psi", + "RPM", "kg", "N", "N·m", "m/s", "m/min", "A", "V", "kW", "%", + "L/min", "Hz", "dB", "ea", "g", "mg", "ml", "L", +]; + +const PLC_DATA_OPTIONS = [ + { value: "PLC_TEMP_01", label: "온도 (PLC_TEMP_01)" }, + { value: "PLC_PRES_01", label: "압력 (PLC_PRES_01)" }, + { value: "PLC_RPM_01", label: "회전수 (PLC_RPM_01)" }, + { value: "PLC_TORQ_01", label: "토크 (PLC_TORQ_01)" }, + { value: "PLC_SPD_01", label: "속도 (PLC_SPD_01)" }, + { value: "PLC_CUR_01", label: "전류 (PLC_CUR_01)" }, + { value: "PLC_VOLT_01", label: "전압 (PLC_VOLT_01)" }, + { value: "PLC_VIB_01", label: "진동 (PLC_VIB_01)" }, + { value: "PLC_HUM_01", label: "습도 (PLC_HUM_01)" }, + { value: "PLC_FLOW_01", label: "유량 (PLC_FLOW_01)" }, +]; + +const PLC_PRODUCTION_OPTIONS = { + work_qty: [ + { value: "PLC_CNT_01", label: "생산카운터 (PLC_CNT_01)" }, + { value: "PLC_CNT_02", label: "완료카운터 (PLC_CNT_02)" }, + { value: "PLC_QTY_01", label: "작업수량 (PLC_QTY_01)" }, + ], + defect_qty: [ + { value: "PLC_NG_01", label: "불량카운터 (PLC_NG_01)" }, + { value: "PLC_NG_02", label: "NG감지기 (PLC_NG_02)" }, + { value: "PLC_REJ_01", label: "리젝트수 (PLC_REJ_01)" }, + ], + good_qty: [ + { value: "PLC_OK_01", label: "양품카운터 (PLC_OK_01)" }, + { value: "PLC_OK_02", label: "합격카운터 (PLC_OK_02)" }, + { value: "PLC_GOOD_01", label: "양품수량 (PLC_GOOD_01)" }, + ], +}; + export function DetailFormModal({ open, onClose, @@ -55,10 +86,35 @@ export function DetailFormModal({ detailTypes, editData, mode, + selectedItemCode, }: DetailFormModalProps) { const [formData, setFormData] = useState>({}); const [inspectionLookupOpen, setInspectionLookupOpen] = useState(false); const [selectedInspection, setSelectedInspection] = useState(null); + const [bomMaterials, setBomMaterials] = useState([]); + const [bomLoading, setBomLoading] = useState(false); + const [bomChecked, setBomChecked] = useState>(new Set()); + + const loadBomMaterials = useCallback(async () => { + if (!selectedItemCode) { + setBomMaterials([]); + return; + } + setBomLoading(true); + try { + const res = await getBomMaterials(selectedItemCode); + if (res.success && res.data) { + setBomMaterials(res.data); + setBomChecked(new Set(res.data.map((m) => m.child_item_id))); + } else { + setBomMaterials([]); + } + } catch { + setBomMaterials([]); + } finally { + setBomLoading(false); + } + }, [selectedItemCode]); useEffect(() => { if (open) { @@ -86,6 +142,12 @@ export function DetailFormModal({ } }, [open, mode, editData, detailTypes]); + useEffect(() => { + if (open && formData.detail_type === "material_input") { + loadBomMaterials(); + } + }, [open, formData.detail_type, loadBomMaterials]); + const updateField = (field: string, value: any) => { setFormData((prev) => ({ ...prev, [field]: value })); }; @@ -108,17 +170,33 @@ export function DetailFormModal({ const type = formData.detail_type; - if (type === "check" && !formData.content?.trim()) return; - if (type === "inspect" && !formData.content?.trim()) return; + if (type === "checklist" && !formData.content?.trim()) return; + if (type === "inspection") { + if (!formData.process_inspection_apply) return; + if (formData.process_inspection_apply === "none" && !formData.content?.trim()) return; + } if (type === "procedure" && !formData.content?.trim()) return; if (type === "input" && !formData.content?.trim()) return; - if (type === "info" && !formData.lookup_target) return; + if (type === "equip_inspection" && !formData.equip_inspection_apply) return; + if (type === "equip_condition" && !formData.content?.trim()) return; const submitData = { ...formData }; - if (type === "info" && !submitData.content?.trim()) { - const targetLabel = LOOKUP_TARGETS.find(t => t.value === submitData.lookup_target)?.label || submitData.lookup_target; - submitData.content = `${targetLabel} 조회`; + // content 자동 설정 (UI에서 직접 입력이 없는 유형들) + if (type === "inspection" && submitData.process_inspection_apply === "apply") { + submitData.content = submitData.content || "품목별 검사정보 (자동 연동)"; + } + if (type === "lookup") { + submitData.content = submitData.content || "품목 등록 문서 (자동 연동)"; + } + if (type === "equip_inspection" && submitData.equip_inspection_apply === "apply") { + submitData.content = submitData.content || "설비 점검항목 (설비정보 연동)"; + } + if (type === "production_result") { + submitData.content = submitData.content || "작업수량 / 불량수량 / 양품수량"; + } + if (type === "material_input") { + submitData.content = submitData.content || "BOM 구성 자재 (자동 연동)"; } onSubmit(submitData); @@ -130,7 +208,7 @@ export function DetailFormModal({ return ( <> !v && onClose()}> - + 상세 항목 {mode === "add" ? "추가" : "수정"} @@ -149,12 +227,11 @@ export function DetailFormModal({ - {/* 체크리스트 */} - {currentType === "check" && ( - <> -
- - updateField("content", e.target.value)} - placeholder="예: 전원 상태 확인" - className="mt-1 h-8 text-xs sm:h-10 sm:text-sm" - /> -
- + {/* ============ 체크리스트 ============ */} + {currentType === "checklist" && ( +
+ + updateField("content", e.target.value)} + placeholder="예: 전원 상태 확인" + className="mt-1 h-8 text-xs sm:h-10 sm:text-sm" + /> +
)} - {/* 검사항목 */} - {currentType === "inspect" && ( + {/* ============ 검사항목 ============ */} + {currentType === "inspection" && ( <> + {/* 공정검사 적용 여부 */}
-
- - +
+ +
- {selectedInspection && ( -
-

- 선택된 검사기준 정보 + {/* 적용 시: 품목별 검사정보 자동 연동 안내 */} + {formData.process_inspection_apply === "apply" && ( +

+

+ 품목별 검사정보 (자동 연동) +

+

+ 품목에 등록된 검사기준이 자동으로 적용됩니다.

-
-

- 검사코드: {selectedInspection.inspection_code} -

-

- 검사항목: {selectedInspection.inspection_item} -

-

- 검사방법: {selectedInspection.inspection_method || "-"} -

-

- 단위: {selectedInspection.unit || "-"} -

-

- 하한값: {selectedInspection.lower_limit || "-"} -

-

- 상한값: {selectedInspection.upper_limit || "-"} -

-
)} -
- - updateField("content", e.target.value)} - placeholder="예: 외경 치수" - className="mt-1 h-8 text-xs sm:h-10 sm:text-sm" - /> -
+ {/* 미적용 시: 수동 입력 */} + {formData.process_inspection_apply === "none" && ( + <> +
+ + updateField("content", e.target.value)} + placeholder="예: 외경 치수" + className="mt-1 h-8 text-xs sm:h-10 sm:text-sm" + /> +
+
+
+ + updateField("inspection_method", e.target.value)} + placeholder="예: 마이크로미터" + className="mt-1 h-8 text-xs sm:h-10 sm:text-sm" + /> +
+
+ + +
+
-
-
- - updateField("inspection_method", e.target.value)} - placeholder="예: 마이크로미터" - className="mt-1 h-8 text-xs sm:h-10 sm:text-sm" - /> -
-
- - updateField("unit", e.target.value)} - placeholder="예: mm" - className="mt-1 h-8 text-xs sm:h-10 sm:text-sm" - /> -
-
+ {/* 기준값 ± 오차범위 */} +
+
+
+ updateField("base_value", e.target.value)} + placeholder="기준값" + className="h-8 text-xs sm:h-10 sm:text-sm" + /> +
+ ± +
+ updateField("tolerance", e.target.value)} + placeholder="오차범위" + className="h-8 text-xs sm:h-10 sm:text-sm" + /> +
+
-
-
- - updateField("lower_limit", e.target.value)} - placeholder="예: 7.95" - className="mt-1 h-8 text-xs sm:h-10 sm:text-sm" - /> -
-
- - updateField("upper_limit", e.target.value)} - placeholder="예: 8.05" - className="mt-1 h-8 text-xs sm:h-10 sm:text-sm" - /> -
-
+ {/* 자동수집 */} +
+ + +
+
+ + )} )} - {/* 작업절차 */} + {/* ============ 작업절차 ============ */} {currentType === "procedure" && ( <>
@@ -322,10 +427,7 @@ export function DetailFormModal({ type="number" value={formData.duration_minutes ?? ""} onChange={(e) => - updateField( - "duration_minutes", - e.target.value ? Number(e.target.value) : undefined - ) + updateField("duration_minutes", e.target.value ? Number(e.target.value) : undefined) } placeholder="예: 5" className="mt-1 h-8 text-xs sm:h-10 sm:text-sm" @@ -334,7 +436,7 @@ export function DetailFormModal({ )} - {/* 직접입력 */} + {/* ============ 직접입력 ============ */} {currentType === "input" && ( <>
@@ -359,9 +461,7 @@ export function DetailFormModal({ {INPUT_TYPES.map((t) => ( - - {t.label} - + {t.label} ))} @@ -369,41 +469,367 @@ export function DetailFormModal({ )} - {/* 정보조회 */} - {currentType === "info" && ( + {/* ============ 문서참조 ============ */} + {currentType === "lookup" && ( <> -
- - +
+ 📄 + + 해당 품목에 등록된 문서를 자동으로 불러옵니다. +
- - updateField("display_fields", e.target.value)} - placeholder="예: 설비명, 설비코드" - className="mt-1 h-8 text-xs sm:h-10 sm:text-sm" - /> + +
+

+ 품목이 선택되지 않았습니다. +

+
)} + {/* ============ 설비점검 ============ */} + {currentType === "equip_inspection" && ( + <> +
+ 🏭 + + 공정에 지정된 설비를 자동 참조합니다. + +
+ +
+ +
+ + +
+
+ + {/* 적용 시: 설비 점검항목 자동 연동 */} + {formData.equip_inspection_apply === "apply" && ( +
+

+ 설비 점검항목 (설비정보 연동) +

+

+ 공정에 지정된 설비의 점검항목이 자동으로 적용됩니다. +

+
+ )} + + )} + + {/* ============ 설비조건 ============ */} + {currentType === "equip_condition" && ( + <> +
+ 🏭 + + 공정에 지정된 설비를 자동 참조합니다. + +
+ +
+ +
+ {/* 조건명 + 단위 */} +
+
+ updateField("content", e.target.value)} + placeholder="조건명 (예: 온도, 압력, RPM)" + className="h-8 text-xs sm:h-10 sm:text-sm" + /> +
+
+ +
+
+ + {/* 기준값 ± 오차범위 */} +
+
+ updateField("condition_base_value", e.target.value)} + placeholder="기준값" + className="h-8 text-xs sm:h-10 sm:text-sm" + /> +
+ ± +
+ updateField("condition_tolerance", e.target.value)} + placeholder="오차범위" + className="h-8 text-xs sm:h-10 sm:text-sm" + /> +
+
+ + {/* 자동수집 */} +
+ + +
+
+
+ + )} + + {/* ============ 실적등록 ============ */} + {currentType === "production_result" && ( +
+ +
+ {/* 작업수량 */} +
+
+ 📦 작업수량 + 생산된 전체 수량 +
+
+ + +
+
+ + {/* 불량수량 */} +
+
+ 🚫 불량수량 + 불량으로 판정된 수량 +
+
+ + +
+
+ + {/* 양품수량 */} +
+
+ ✅ 양품수량 + 작업수량 - 불량수량 +
+
+ + +
+
+
+
+ )} + + {/* ============ 자재투입 ============ */} + {currentType === "material_input" && ( +
+ +
+
+

+ 📦 BOM 구성 자재 (자동 연동) +

+ + {bomMaterials.length > 0 ? `${bomMaterials.length}건` : ""} + +
+
+ {bomLoading ? ( +
+ + BOM 데이터를 불러오는 중... +
+ ) : !selectedItemCode ? ( +
+ 품목을 먼저 선택하세요. +
+ ) : bomMaterials.length === 0 ? ( +
+ 해당 품목의 BOM 구성 자재가 없습니다. +
+ ) : ( + bomMaterials.map((mat) => { + const typeColor = + mat.child_item_type === "원자재" ? "#16a34a" + : mat.child_item_type === "반제품" ? "#2563eb" + : "#6b7280"; + return ( +
+ { + setBomChecked((prev) => { + const next = new Set(prev); + if (checked) next.add(mat.child_item_id); + else next.delete(mat.child_item_id); + return next; + }); + }} + /> +
+
+ {mat.child_item_type && ( + + {mat.child_item_type} + + )} + + {mat.child_item_code || "-"} + + + {mat.child_item_name || "(이름 없음)"} + +
+
+ 소요량: {mat.quantity || "0"} {mat.detail_unit || mat.item_unit || ""} + {mat.process_type ? ` | 공정: ${mat.process_type}` : ""} +
+
+
+ ); + }) + )} +
+
+
+ )} + {/* 필수 여부 (모든 유형 공통) */} {currentType && (
diff --git a/frontend/lib/registry/components/v2-process-work-standard/components/WorkItemDetailList.tsx b/frontend/lib/registry/components/v2-process-work-standard/components/WorkItemDetailList.tsx index 89d1b464..7b2979e1 100644 --- a/frontend/lib/registry/components/v2-process-work-standard/components/WorkItemDetailList.tsx +++ b/frontend/lib/registry/components/v2-process-work-standard/components/WorkItemDetailList.tsx @@ -13,6 +13,7 @@ interface WorkItemDetailListProps { details: WorkItemDetail[]; detailTypes: DetailTypeDefinition[]; readonly?: boolean; + selectedItemCode?: string; onCreateDetail: (data: Partial) => void; onUpdateDetail: (id: string, data: Partial) => void; onDeleteDetail: (id: string) => void; @@ -23,6 +24,7 @@ export function WorkItemDetailList({ details, detailTypes, readonly, + selectedItemCode, onCreateDetail, onUpdateDetail, onDeleteDetail, @@ -66,11 +68,12 @@ export function WorkItemDetailList({ const getContentSummary = (detail: WorkItemDetail): string => { const type = detail.detail_type; - if (type === "inspect" && detail.inspection_code) { + if (type === "inspection") { + if (detail.process_inspection_apply === "apply") return "품목별 검사정보 (자동 연동)"; const parts = [detail.content]; if (detail.inspection_method) parts.push(`[${detail.inspection_method}]`); - if (detail.lower_limit || detail.upper_limit) { - parts.push(`(${detail.lower_limit || "-"} ~ ${detail.upper_limit || "-"} ${detail.unit || ""})`); + if (detail.base_value) { + parts.push(`(기준: ${detail.base_value}${detail.tolerance ? ` ±${detail.tolerance}` : ""} ${detail.unit || ""})`); } return parts.join(" "); } @@ -83,20 +86,24 @@ export function WorkItemDetailList({ number: "숫자", date: "날짜", textarea: "장문", - select: "선택형", }; return `${detail.content} [${typeMap[detail.input_type] || detail.input_type}]`; } - if (type === "info" && detail.lookup_target) { - const targetMap: Record = { - equipment: "설비정보", - material: "자재정보", - worker: "작업자정보", - tool: "공구정보", - document: "문서정보", - }; - return `${targetMap[detail.lookup_target] || detail.lookup_target} 조회`; + if (type === "lookup") return "품목 등록 문서 (자동 연동)"; + if (type === "equip_inspection") { + return detail.equip_inspection_apply === "apply" + ? "설비 점검항목 (설비정보 연동)" + : detail.content || "설비점검"; } + if (type === "equip_condition") { + const parts = [detail.content]; + if (detail.condition_base_value) { + parts.push(`(기준: ${detail.condition_base_value}${detail.condition_tolerance ? ` ±${detail.condition_tolerance}` : ""} ${detail.condition_unit || ""})`); + } + return parts.join(" "); + } + if (type === "production_result") return "작업수량 / 불량수량 / 양품수량"; + if (type === "material_input") return "BOM 구성 자재 (자동 연동)"; return detail.content || "-"; }; @@ -214,6 +221,7 @@ export function WorkItemDetailList({ detailTypes={detailTypes} editData={editTarget} mode={modalMode} + selectedItemCode={selectedItemCode} />
); diff --git a/frontend/lib/registry/components/v2-process-work-standard/components/WorkPhaseSection.tsx b/frontend/lib/registry/components/v2-process-work-standard/components/WorkPhaseSection.tsx index 1f2e7e4a..dcfc2a96 100644 --- a/frontend/lib/registry/components/v2-process-work-standard/components/WorkPhaseSection.tsx +++ b/frontend/lib/registry/components/v2-process-work-standard/components/WorkPhaseSection.tsx @@ -20,6 +20,7 @@ interface WorkPhaseSectionProps { selectedWorkItemDetails: WorkItemDetail[]; detailTypes: DetailTypeDefinition[]; readonly?: boolean; + selectedItemCode?: string; onSelectWorkItem: (workItemId: string, phaseKey: string) => void; onAddWorkItem: (phase: string) => void; onEditWorkItem: (item: WorkItem) => void; @@ -36,6 +37,7 @@ export function WorkPhaseSection({ selectedWorkItemDetails, detailTypes, readonly, + selectedItemCode, onSelectWorkItem, onAddWorkItem, onEditWorkItem, @@ -107,6 +109,7 @@ export function WorkPhaseSection({ details={selectedWorkItemDetails} detailTypes={detailTypes} readonly={readonly} + selectedItemCode={selectedItemCode} onCreateDetail={(data) => selectedWorkItemId && onCreateDetail(selectedWorkItemId, data, phase.key) } diff --git a/frontend/lib/registry/components/v2-process-work-standard/config.ts b/frontend/lib/registry/components/v2-process-work-standard/config.ts index 22b36ea3..4a13fa56 100644 --- a/frontend/lib/registry/components/v2-process-work-standard/config.ts +++ b/frontend/lib/registry/components/v2-process-work-standard/config.ts @@ -23,10 +23,15 @@ export const defaultConfig: ProcessWorkStandardConfig = { { key: "POST", label: "작업 후 (Post-Work)", sortOrder: 3 }, ], detailTypes: [ - { value: "check", label: "체크리스트" }, - { value: "inspect", label: "검사항목" }, + { value: "checklist", label: "체크리스트" }, + { value: "inspection", label: "검사항목" }, { value: "procedure", label: "작업절차" }, { value: "input", label: "직접입력" }, + { value: "lookup", label: "문서참조" }, + { value: "equip_inspection", label: "설비점검" }, + { value: "equip_condition", label: "설비조건" }, + { value: "production_result", label: "실적등록" }, + { value: "material_input", label: "자재투입" }, ], splitRatio: 30, leftPanelTitle: "품목 및 공정 선택", diff --git a/frontend/lib/registry/components/v2-process-work-standard/types.ts b/frontend/lib/registry/components/v2-process-work-standard/types.ts index 7185429b..457fb999 100644 --- a/frontend/lib/registry/components/v2-process-work-standard/types.ts +++ b/frontend/lib/registry/components/v2-process-work-standard/types.ts @@ -91,19 +91,53 @@ export interface WorkItemDetail { sort_order: number; remark?: string; created_date?: string; - // 검사항목 전용 + + // 검사항목(inspection) 전용 + process_inspection_apply?: string; // "apply" | "none" inspection_code?: string; inspection_method?: string; unit?: string; + base_value?: string; + tolerance?: string; lower_limit?: string; upper_limit?: string; - // 작업절차 전용 + auto_collect?: string; // "Y" | "N" + plc_data?: string; + + // 작업절차(procedure) 전용 duration_minutes?: number; - // 직접입력 전용 + + // 직접입력(input) 전용 input_type?: string; - // 정보조회 전용 + + // 문서참조(lookup) 전용 lookup_target?: string; display_fields?: string; + + // 설비점검(equip_inspection) 전용 + equip_inspection_apply?: string; // "apply" | "none" + + // 설비조건(equip_condition) 전용 + condition_name?: string; + condition_unit?: string; + condition_base_value?: string; + condition_tolerance?: string; + condition_auto_collect?: string; + condition_plc_data?: string; + + // 실적등록(production_result) 전용 + work_qty_auto_collect?: string; + work_qty_plc_data?: string; + defect_qty_auto_collect?: string; + defect_qty_plc_data?: string; + good_qty_auto_collect?: string; + good_qty_plc_data?: string; + + // 자재투입(material_input) 전용 - BOM 자동연동 + material_code?: string; + material_name?: string; + quantity?: string; + material_unit?: string; } export interface InspectionStandard {