From 9567d7f7ce8a6a79112611c03af9537f39da239d Mon Sep 17 00:00:00 2001 From: rsone001 Date: Thu, 19 Mar 2026 15:09:03 +0900 Subject: [PATCH] =?UTF-8?q?st:=20fix:=20=EC=88=98=EC=8B=9D=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D=20=EC=9C=A0=ED=9A=A8=EC=84=B1=EA=B2=80=EC=82=AC=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../generalVerification/DetailComponent.tsx | 44 ++++++++++++++++--- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/apps/st/src/components/statistics/verification/generalVerification/DetailComponent.tsx b/apps/st/src/components/statistics/verification/generalVerification/DetailComponent.tsx index f976488f0..0f9da9e01 100644 --- a/apps/st/src/components/statistics/verification/generalVerification/DetailComponent.tsx +++ b/apps/st/src/components/statistics/verification/generalVerification/DetailComponent.tsx @@ -69,11 +69,28 @@ const DetailComponent = ({ selectedVrfcRow }: DetailComponentProps) => { cmprOpert: row?.cmprOpert ?? null, })); - if (rows.length < 2) { - alert('수식 항목은 최소 2개 이상 등록해야 합니다.'); + const UNARY_TERMINAL_OPERATORS = new Set(['is_null', '!is_null', 'floor']); + const lastOperator = rows.at(-1)?.cmprOpert ?? null; + const lastIsUnary = rows.length > 0 && lastOperator != null && UNARY_TERMINAL_OPERATORS.has(lastOperator); + const isSingleUnaryFormula = rows.length === 1 && lastIsUnary; + + // 단항 연산자일 때만 row 1개 허용 + if (rows.length === 1 && !isSingleUnaryFormula) { + alert('해당 연산자는 최소 2개 항목이 필요합니다.'); return; } + // 단항 연산자(is_null, !is_null, floor)는 반드시 맨 마지막 항목에만 허용 + if (rows.length > 1) { + const unaryAtWrongIdx = rows.findIndex( + (r, idx) => idx < rows.length - 1 && r.cmprOpert != null && UNARY_TERMINAL_OPERATORS.has(r.cmprOpert), + ); + if (unaryAtWrongIdx !== -1) { + alert(`단항 연산자(is_null, !is_null, floor)는 맨 마지막 항목에만 사용할 수 있습니다.\n(순번: ${unaryAtWrongIdx + 1})`); + return; + } + } + const invalidIdx = rows.findIndex( (r) => r.kornArtopnEqtnCn.trim().length === 0 || r.engArtopnEqtnCn.trim().length === 0, ); @@ -82,8 +99,8 @@ const DetailComponent = ({ selectedVrfcRow }: DetailComponentProps) => { return; } - // 마지막을 제외한 항목들은 연산자(cmprOpert)가 반드시 있어야 함 - if (rows.length > 1) { + // 마지막이 단항 연산자가 아닐 때만: 마지막을 제외한 항목들은 연산자(cmprOpert) 필수 + if (rows.length > 1 && !lastIsUnary) { const invalidOpertIdx = rows.slice(0, -1).findIndex((r) => r.cmprOpert == null); if (invalidOpertIdx !== -1) { alert(`연산자가 선택되지 않은 항목이 있습니다.\n(순번: ${invalidOpertIdx + 1})`); @@ -91,8 +108,23 @@ const DetailComponent = ({ selectedVrfcRow }: DetailComponentProps) => { } } - // 마지막 항목의 연산자는 무조건 null 처리 - if (rows.length > 0) { + // 여러 항목일 때 마지막이 단항 연산자면: 이전 항목들 연산자는 무조건 null + if (rows.length > 1 && lastIsUnary) { + for (let i = 0; i < rows.length - 1; i++) { + const prev = rows[i]; + if (prev) prev.cmprOpert = null; + } + setFormulaList((prev) => { + if (prev.length <= 1) return prev; + const next = prev.map((item, idx) => + idx < prev.length - 1 && item != null ? { ...item, cmprOpert: null } : item, + ); + return next; + }); + } + + // 마지막 항목의 연산자는 (단항 연산자 케이스 제외) 무조건 null 처리 + if (rows.length > 1 && !lastIsUnary) { const lastRow = rows[rows.length - 1]; if (lastRow) lastRow.cmprOpert = null; setFormulaList((prev) => {