From f1773b76c3df25f823ceca078681678869179404 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=ED=98=81=EC=84=B1?= Date: Fri, 20 Mar 2026 12:39:34 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20[inspection]=20=EC=99=84=EB=A3=8C?= =?UTF-8?q?=EB=90=9C=20=EA=B2=80=EC=82=AC=20=EB=AA=A8=EB=8B=AC=20readonly?= =?UTF-8?q?=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ProductInspectionInputModal에 readonly prop 추가 - 완료 상태: 적합/부적합 버튼, input, textarea 모두 disabled - 일괄합격/초기화 버튼, 저장 버튼, 사진 업로드/삭제 숨김 - 이전/다음 네비게이션 시 저장 방지 - InspectionDetail에서 status=완료 시 readonly 전달 --- .../InspectionManagement/InspectionDetail.tsx | 1 + .../ProductInspectionInputModal.tsx | 213 +++++++++++------- 2 files changed, 130 insertions(+), 84 deletions(-) diff --git a/src/components/quality/InspectionManagement/InspectionDetail.tsx b/src/components/quality/InspectionManagement/InspectionDetail.tsx index 1e38f786..39ffc3a1 100644 --- a/src/components/quality/InspectionManagement/InspectionDetail.tsx +++ b/src/components/quality/InspectionManagement/InspectionDetail.tsx @@ -1414,6 +1414,7 @@ export function InspectionDetail({ id }: InspectionDetailProps) { changeReason={selectedOrderItem?.changeReason} orderItems={isEditMode ? formData.orderItems : (inspection?.orderItems || [])} onNavigate={(item) => setSelectedOrderItem(item)} + readonly={inspection?.status === '완료'} /> ); diff --git a/src/components/quality/InspectionManagement/ProductInspectionInputModal.tsx b/src/components/quality/InspectionManagement/ProductInspectionInputModal.tsx index 6ff11a8c..eeaabce1 100644 --- a/src/components/quality/InspectionManagement/ProductInspectionInputModal.tsx +++ b/src/components/quality/InspectionManagement/ProductInspectionInputModal.tsx @@ -53,6 +53,8 @@ interface ProductInspectionInputModalProps { orderItems?: OrderSettingItem[]; /** 이전/다음 이동 시 호출 (저장 후 해당 아이템으로 전환) */ onNavigate?: (item: OrderSettingItem) => void; + /** 읽기전용 모드 (완료된 검사) */ + readonly?: boolean; } export function ProductInspectionInputModal({ @@ -69,6 +71,7 @@ export function ProductInspectionInputModal({ changeReason: initialChangeReason = '', orderItems = [], onNavigate, + readonly = false, }: ProductInspectionInputModalProps) { // FQC 모드 상태 const [fqcTemplate, setFqcTemplate] = useState(null); @@ -302,13 +305,16 @@ export function ProductInspectionInputModal({ const saveAndNavigate = useCallback(async (targetItem: OrderSettingItem) => { if (!onNavigate) return; - // 변경된 내용이 있을 때만 저장 - if (useFqcMode) { - // FQC: judgments 변경 확인 - const hasJudgmentChanges = Object.keys(judgments).length > 0; - if (hasJudgmentChanges) await handleFqcComplete(false); - } else if (legacyFormData && hasLegacyChanges()) { - onComplete(legacyFormData, { width: conWidth, height: conHeight, changeReason }); + // readonly 모드에서는 저장 없이 이동만 + if (!readonly) { + // 변경된 내용이 있을 때만 저장 + if (useFqcMode) { + // FQC: judgments 변경 확인 + const hasJudgmentChanges = Object.keys(judgments).length > 0; + if (hasJudgmentChanges) await handleFqcComplete(false); + } else if (legacyFormData && hasLegacyChanges()) { + onComplete(legacyFormData, { width: conWidth, height: conHeight, changeReason }); + } } // 다음 아이템으로 이동 onNavigate(targetItem); @@ -397,8 +403,9 @@ export function ProductInspectionInputModal({ type="number" value={conWidth ?? ''} onChange={(e) => setConWidth(e.target.value ? Number(e.target.value) : null)} - className="w-full h-9 px-3 rounded-md border border-input bg-background text-sm" + className={cn("w-full h-9 px-3 rounded-md border border-input bg-background text-sm", readonly && "bg-muted cursor-not-allowed")} placeholder="가로" + disabled={readonly} />
@@ -407,8 +414,9 @@ export function ProductInspectionInputModal({ type="number" value={conHeight ?? ''} onChange={(e) => setConHeight(e.target.value ? Number(e.target.value) : null)} - className="w-full h-9 px-3 rounded-md border border-input bg-background text-sm" + className={cn("w-full h-9 px-3 rounded-md border border-input bg-background text-sm", readonly && "bg-muted cursor-not-allowed")} placeholder="세로" + disabled={readonly} />
@@ -417,8 +425,9 @@ export function ProductInspectionInputModal({ type="text" value={changeReason} onChange={(e) => setChangeReason(e.target.value)} - className="w-full h-9 px-3 rounded-md border border-input bg-background text-sm" + className={cn("w-full h-9 px-3 rounded-md border border-input bg-background text-sm", readonly && "bg-muted cursor-not-allowed")} placeholder="변경사유 입력" + disabled={readonly} />
@@ -441,7 +450,7 @@ export function ProductInspectionInputModal({ ({sortedItems.length}항목) - {(() => { + {!readonly && (() => { const allPassed = sortedItems.length > 0 && sortedItems.every((_, idx) => judgments[idx] === '적합'); return allPassed ? ( - + {!readonly && ( + + )} @@ -541,11 +554,13 @@ function FqcInspectionRow({ item, judgment, onToggle, + readonly = false, }: { index: number; item: FqcTemplateItem; judgment: JudgmentValue; onToggle: (rowIndex: number, value: JudgmentValue) => void; + readonly?: boolean; }) { return (
@@ -556,24 +571,32 @@ function FqcInspectionRow({
- ) : ( - - )} -
+ {!readonly && ( +
+ {allPassed ? ( + + ) : ( + + )} +
+ )} {/* 1. 겉모양 검사 */} - update('appearanceProcessing', v)} /> - update('appearanceSewing', v)} /> - update('appearanceAssembly', v)} /> - update('appearanceSmokeBarrier', v)} /> - update('appearanceBottomFinish', v)} /> + update('appearanceProcessing', v)} readonly={readonly} /> + update('appearanceSewing', v)} readonly={readonly} /> + update('appearanceAssembly', v)} readonly={readonly} /> + update('appearanceSmokeBarrier', v)} readonly={readonly} /> + update('appearanceBottomFinish', v)} readonly={readonly} /> {/* 2. 모터 */} - update('motor', v)} /> + update('motor', v)} readonly={readonly} /> {/* 3. 재질 */} - update('material', v)} /> + update('material', v)} readonly={readonly} /> {/* 4. 치수(오픈사이즈) */} - update('lengthJudgment', v)} /> - update('heightJudgment', v)} /> - update('guideRailGap', v)} /> - update('bottomFinishGap', v)} /> + update('lengthJudgment', v)} readonly={readonly} /> + update('heightJudgment', v)} readonly={readonly} /> + update('guideRailGap', v)} readonly={readonly} /> + update('bottomFinishGap', v)} readonly={readonly} /> {/* 5~9. 시험 검사 */} - update('fireResistanceTest', v)} /> - update('smokeLeakageTest', v)} /> - update('openCloseTest', v)} /> - update('impactTest', v)} /> + update('fireResistanceTest', v)} readonly={readonly} /> + update('smokeLeakageTest', v)} readonly={readonly} /> + update('openCloseTest', v)} readonly={readonly} /> + update('impactTest', v)} readonly={readonly} /> {/* 사진 첨부 */} @@ -674,6 +701,7 @@ function LegacyInspectionForm({ images={data.productImages} onChange={(images) => update('productImages', images)} maxCount={2} + readonly={readonly} /> {/* 특이사항 */} @@ -681,8 +709,9 @@ function LegacyInspectionForm({