diff --git a/apps/st/src/components/module/DataGrid.tsx b/apps/st/src/components/module/DataGrid.tsx index fea761a3f..dd2f84f6f 100644 --- a/apps/st/src/components/module/DataGrid.tsx +++ b/apps/st/src/components/module/DataGrid.tsx @@ -955,7 +955,7 @@ const DataGrid = ({ try { gv.commit?.(); } catch { - /* ignore */ + console.error('commit error'); } const ds = gv.getDataSource(); if (!ds) return rowDataRef.current.map((r) => ({ ...r })); @@ -1954,7 +1954,7 @@ useEffect(() => { } | undefined; if (!gv?.getDataSource) return []; - try { gv.commit?.(); } catch { /* ignore */ } + try { gv.commit?.(); } catch { console.error('commit error'); } const ds = gv.getDataSource(); if (!ds) return []; const cnt = ds.getRowCount(); @@ -2022,7 +2022,7 @@ useEffect(() => { column.footer.styleName = styleName; } } catch { - /* ignore */ + console.error('총계 스타일 재적용/초기화 error'); } }); gridView.refresh?.(); diff --git a/apps/st/src/components/module/SearchForm.tsx b/apps/st/src/components/module/SearchForm.tsx index cf953ca51..fc1a3ca5f 100644 --- a/apps/st/src/components/module/SearchForm.tsx +++ b/apps/st/src/components/module/SearchForm.tsx @@ -236,12 +236,13 @@ const SearchForm = (props: SearchFormProps = {}) => { const sggOptions = sggList?.data ?? []; const isDoSelected = isDoSido(selectedSido); const firstConcreteSggOption = firstConcreteSgg(sggOptions); + // 도: 빈 값일 때만 첫 시군구로 보이게. ALL은 사용자가 고른 전체 유지 const gugunSelectValue = - isDoSelected && isAllGugunValue(values.gugun) + isDoSelected && !values.gugun ? (firstConcreteSggOption?.gugun ?? undefined) : values.gugun || undefined; - // 도: 전체(ALL/"")가 아니라 그 다음 시군구. 그 외: 전체 + // 도: 초기/시도 변경(빈 값)만 첫 시군구. 전체(ALL)는 유지. 그 외: 전체 useEffect(() => { if (!mergedProps.gugun) return; if (props.defaultRegionAll) return; @@ -263,7 +264,7 @@ const SearchForm = (props: SearchFormProps = {}) => { if (!firstConcreteSggOption) return; setValues((prev) => { - if (!isAllGugunValue(prev.gugun)) return prev; + if (prev.gugun) return prev; return { ...prev, gugun: firstConcreteSggOption.gugun, diff --git a/apps/st/src/components/module/TabDataGrid.tsx b/apps/st/src/components/module/TabDataGrid.tsx index 04b372333..3da27a42d 100644 --- a/apps/st/src/components/module/TabDataGrid.tsx +++ b/apps/st/src/components/module/TabDataGrid.tsx @@ -104,7 +104,7 @@ function safeGridViewRefresh(gv: { refresh?: () => void } | null | undefined) { try { gv.refresh(); } catch { - /* noop */ + console.error('refresh error'); } } diff --git a/apps/st/src/components/module/VerificationResultDialog.tsx b/apps/st/src/components/module/VerificationResultDialog.tsx index f52eeb1d1..4fda1f5a0 100644 --- a/apps/st/src/components/module/VerificationResultDialog.tsx +++ b/apps/st/src/components/module/VerificationResultDialog.tsx @@ -68,7 +68,7 @@ function setRowCheckByItemIndex( try { gv?.checkItem?.(itemIndex, checked, false); } catch { - /* RealGrid 체크 API 미지원 등 */ + console.error('RealGrid 체크 API error'); } } diff --git a/apps/st/src/components/module/VerificationResultHistoryDialog.tsx b/apps/st/src/components/module/VerificationResultHistoryDialog.tsx index 958ccf40d..9eff0b060 100644 --- a/apps/st/src/components/module/VerificationResultHistoryDialog.tsx +++ b/apps/st/src/components/module/VerificationResultHistoryDialog.tsx @@ -91,7 +91,7 @@ function uncheckGridRow(gridRef: MutableRefObject, itemInd try { (gridRef.current?.gridView as GridViewWithCheckApi | undefined)?.checkItem?.(itemIndex, false, false); } catch { - /* ignore */ + console.error('RealGrid 체크 API error'); } } diff --git a/apps/st/src/components/statistics/input/SewagePipeInp.tsx b/apps/st/src/components/statistics/input/SewagePipeInp.tsx index 6a348cef5..817c63d93 100644 --- a/apps/st/src/components/statistics/input/SewagePipeInp.tsx +++ b/apps/st/src/components/statistics/input/SewagePipeInp.tsx @@ -13,9 +13,7 @@ import { statisticsApi } from "@/entities/statistics/api/statistics-service"; import type { SeweragePipeInputFactInstallStatusSaveRequest, SeweragePipeInputFactInstallStatusSubmitRequest, - SeweragePipeInputManholeStatusItem, SeweragePipeInputManholeStatusSaveRequest, - SeweragePipeInputManholeStatusSaveYearlyStatItem, SeweragePipeInputManholeStatusSubmitRequest, SeweragePipeInputPipeDiameterStatusSaveRequest, SeweragePipeInputPipeDiameterStatusSubmitRequest, @@ -221,11 +219,6 @@ const applyPipeTypeStatusEditableColumns = ( }); }; -const getManholeLastDataYear = () => { - const lastDataYear = new Date().getFullYear() - 1; - return Math.max(2014, lastDataYear); -}; - /** 2-3 관종별: verificationResult.prlgWhol → 총계 계(pipeByPrstWhol) */ function remapPipeTypePrlgWholVerification( result?: SeweragePipeInputVerificationResult | null, @@ -280,43 +273,6 @@ function normalizePipeTypeStatusRow( }; } -/** 맨홀 신 응답(yearlyStats) -> 그리드 yy{14..25}* 필드로 정규화 */ -function normalizeManholeStatusRow( - row: SeweragePipeInputManholeStatusItem, - ctpvNm: string, -): Record { - const maxYy = getManholeLastDataYear() % 100; - const { yearlyStats, ...rest } = row; - const yearFields: Record = {}; - for (let yy = 14; yy <= maxYy; yy++) { - yearFields[`yy${yy}WholMnhlCnt`] = 0; - yearFields[`yy${yy}Step1MnhlCnt`] = 0; - yearFields[`yy${yy}Step2MnhlCnt`] = 0; - yearFields[`yy${yy}Step3MnhlCnt`] = 0; - yearFields[`yy${yy}Step4MnhlCnt`] = 0; - yearFields[`yy${yy}Step5MnhlCnt`] = 0; - } - - for (const y of yearlyStats ?? []) { - const year = Number(y.manhYr); - if (!Number.isFinite(year)) continue; - const yy = year % 100; - if (yy < 14 || yy > maxYy) continue; - yearFields[`yy${yy}WholMnhlCnt`] = Number(y.wholMnhlCnt ?? 0); - yearFields[`yy${yy}Step1MnhlCnt`] = Number(y.step1MnhlCnt ?? 0); - yearFields[`yy${yy}Step2MnhlCnt`] = Number(y.step2MnhlCnt ?? 0); - yearFields[`yy${yy}Step3MnhlCnt`] = Number(y.step3MnhlCnt ?? 0); - yearFields[`yy${yy}Step4MnhlCnt`] = Number(y.step4MnhlCnt ?? 0); - yearFields[`yy${yy}Step5MnhlCnt`] = Number(y.step5MnhlCnt ?? 0); - } - - return { - ctpvNm, - ...rest, - ...yearFields, - }; -} - /** ST00020006(연결)은 행이 좌·우 그리드 키에만 있음 */ type GridRowWithVerification = Record & { verificationResult?: SeweragePipeInputVerificationResult; @@ -884,9 +840,10 @@ const SewagePipeInp = () => { const response = await statisticsInputSewPipeApiService.getManholeStatus(searchParam); if (response.status === 'success') { const commonInfo = response.data.commonInfo; - const convertedData = filterFetched(response.data.manholeStatusList).map((d) => - normalizeManholeStatusRow(d, commonInfo.ctpvNm), - ); + const convertedData = filterFetched(response.data.manholeStatusList).map((d) => ({ + ctpvNm: commonInfo.ctpvNm, + ...d, + })); applyRowMap((m) => m.set('ST00020005', toGridRows(convertedData))); setTabStatusInfoMap((prev) => new Map(prev).set(tabKey, response.data.statusInfo)); setTabStatsCdMap((prev) => new Map(prev).set(tabKey, commonInfo.statsCd)); @@ -1434,36 +1391,17 @@ const SewagePipeInp = () => { const decimalPlaces = format.match(/\.(\d+)/)?.[1]?.length ?? 0; return decimalPlaces > 0 ? parseFloat(num.toFixed(decimalPlaces)) : Math.round(num); }; - const minYy = 14; - const maxYy = getManholeLastDataYear() % 100; - const submitList = currentData.map((d) => { - const yearlyStats: SeweragePipeInputManholeStatusSaveYearlyStatItem[] = []; - for (let yy = minYy; yy <= maxYy; yy++) { - const year = 2000 + yy; - const wholKey = `yy${yy}WholMnhlCnt`; - const step1Key = `yy${yy}Step1MnhlCnt`; - const step2Key = `yy${yy}Step2MnhlCnt`; - const step3Key = `yy${yy}Step3MnhlCnt`; - const step4Key = `yy${yy}Step4MnhlCnt`; - const step5Key = `yy${yy}Step5MnhlCnt`; - yearlyStats.push({ - manhYr: String(year), - wholMnhlCnt: formatNumber(d[wholKey] as string | number | undefined, wholKey), - step1MnhlCnt: formatNumber(d[step1Key] as string | number | undefined, step1Key), - step2MnhlCnt: formatNumber(d[step2Key] as string | number | undefined, step2Key), - step3MnhlCnt: formatNumber(d[step3Key] as string | number | undefined, step3Key), - step4MnhlCnt: formatNumber(d[step4Key] as string | number | undefined, step4Key), - step5MnhlCnt: formatNumber(d[step5Key] as string | number | undefined, step5Key), - }); - } - return { - emphsMngSeCd: nullableTrimmedString(d.emphsMngSeCd), - admdstCd: nullableTrimmedString(d.admdstCd), - admdstNm: nullableTrimmedString(d.admdstNm), - yearlyStats, - rmrk: nullableTrimmedString(d.rmrk), - }; - }); + const submitList = currentData.map((d) => ({ + admdstCd: nullableTrimmedString(d.admdstCd), + admdstNm: nullableTrimmedString(d.admdstNm), + emphsMngSeCd: nullableTrimmedString(d.emphsMngSeCd), + frlvlMnhlCnt: formatNumber(d.frlvlMnhlCnt, "frlvlMnhlCnt"), + sclvlMnhlCnt: formatNumber(d.sclvlMnhlCnt, "sclvlMnhlCnt"), + thlvlMnhlCnt: formatNumber(d.thlvlMnhlCnt, "thlvlMnhlCnt"), + folvlMnhlCnt: formatNumber(d.folvlMnhlCnt, "folvlMnhlCnt"), + filvlMnhlCnt: formatNumber(d.filvlMnhlCnt, "filvlMnhlCnt"), + rmrk: nullableTrimmedString(d.rmrk), + })); const requestData: SeweragePipeInputManholeStatusSubmitRequest = { ...submitBase, submitList, @@ -1989,37 +1927,17 @@ const SewagePipeInp = () => { return decimalPlaces > 0 ? parseFloat(num.toFixed(decimalPlaces)) : Math.round(num); }; - const minYy = 14; - const maxYy = getManholeLastDataYear() % 100; - - const saveList = currentData.map((d) => { - const yearlyStats: SeweragePipeInputManholeStatusSaveYearlyStatItem[] = []; - for (let yy = minYy; yy <= maxYy; yy++) { - const year = 2000 + yy; - const wholKey = `yy${yy}WholMnhlCnt`; - const step1Key = `yy${yy}Step1MnhlCnt`; - const step2Key = `yy${yy}Step2MnhlCnt`; - const step3Key = `yy${yy}Step3MnhlCnt`; - const step4Key = `yy${yy}Step4MnhlCnt`; - const step5Key = `yy${yy}Step5MnhlCnt`; - yearlyStats.push({ - manhYr: String(year), - wholMnhlCnt: formatNumber(d[wholKey] as string | number | undefined, wholKey), - step1MnhlCnt: formatNumber(d[step1Key] as string | number | undefined, step1Key), - step2MnhlCnt: formatNumber(d[step2Key] as string | number | undefined, step2Key), - step3MnhlCnt: formatNumber(d[step3Key] as string | number | undefined, step3Key), - step4MnhlCnt: formatNumber(d[step4Key] as string | number | undefined, step4Key), - step5MnhlCnt: formatNumber(d[step5Key] as string | number | undefined, step5Key), - }); - } - return { - emphsMngSeCd: nullableTrimmedString(d.emphsMngSeCd), - admdstCd: nullableTrimmedString(d.admdstCd), - admdstNm: nullableTrimmedString(d.admdstNm), - yearlyStats, - rmrk: nullableTrimmedString(d.rmrk), - }; - }); + const saveList = currentData.map((d) => ({ + admdstCd: nullableTrimmedString(d.admdstCd), + admdstNm: nullableTrimmedString(d.admdstNm), + emphsMngSeCd: nullableTrimmedString(d.emphsMngSeCd), + frlvlMnhlCnt: formatNumber(d.frlvlMnhlCnt, "frlvlMnhlCnt"), + sclvlMnhlCnt: formatNumber(d.sclvlMnhlCnt, "sclvlMnhlCnt"), + thlvlMnhlCnt: formatNumber(d.thlvlMnhlCnt, "thlvlMnhlCnt"), + folvlMnhlCnt: formatNumber(d.folvlMnhlCnt, "folvlMnhlCnt"), + filvlMnhlCnt: formatNumber(d.filvlMnhlCnt, "filvlMnhlCnt"), + rmrk: nullableTrimmedString(d.rmrk), + })); const userInfo = await getUserInfo(); const param: SeweragePipeInputManholeStatusSaveRequest = { diff --git a/apps/st/src/components/statistics/review/ReviewOpinionDialog.tsx b/apps/st/src/components/statistics/review/ReviewOpinionDialog.tsx index 8ddde5566..ac2232999 100644 --- a/apps/st/src/components/statistics/review/ReviewOpinionDialog.tsx +++ b/apps/st/src/components/statistics/review/ReviewOpinionDialog.tsx @@ -103,7 +103,7 @@ export function ReviewOpinionDialog({ resetForm(); onOpenChange(false); } catch { - /* 저장 실패 시 부모에서 alert 후 throw — 다이얼로그는 유지 */ + console.error('검토 의견 저장 error'); } finally { setIsSaving(false); } diff --git a/apps/st/src/components/statistics/review/SewagePipeRvw.tsx b/apps/st/src/components/statistics/review/SewagePipeRvw.tsx index c0ae50110..29ec2f8f4 100644 --- a/apps/st/src/components/statistics/review/SewagePipeRvw.tsx +++ b/apps/st/src/components/statistics/review/SewagePipeRvw.tsx @@ -32,7 +32,7 @@ import type { ColumnLayoutItem, } from "@/components/type/DataGrid.type"; import type { SearchFormValues } from "@/components/type/SearchForm.type"; -import { getST00020003RvwConfig, getST00020005RvwConfig,SewagePipeColumnInfoListRvw } from "@/components/util/column/review/SewagePipeRvwColumn"; +import { getST00020003RvwConfig,SewagePipeColumnInfoListRvw } from "@/components/util/column/review/SewagePipeRvwColumn"; import { toGridRows } from "@/components/util/grid/gridFunction"; import { buildReviewCellStyleCallbackByTab } from "@/components/util/grid/reviewEmptyCurrCellStyle"; @@ -151,11 +151,9 @@ const SewagePipeRvw = () => { () => { const statsYr = lastSearchValues?.year ?? new Date().getFullYear(); const st00020003Config = getST00020003RvwConfig(statsYr); - const st00020005Config = getST00020005RvwConfig(statsYr); return SewagePipeColumnInfoListRvw.map((tab) => { const source = tab.tabKey === "ST00020003" ? st00020003Config - : tab.tabKey === "ST00020005" ? st00020005Config : tab; return { ...source, diff --git a/apps/st/src/components/statistics/total/SewagePipeTot.tsx b/apps/st/src/components/statistics/total/SewagePipeTot.tsx index 217db48dc..0c120fb5a 100644 --- a/apps/st/src/components/statistics/total/SewagePipeTot.tsx +++ b/apps/st/src/components/statistics/total/SewagePipeTot.tsx @@ -11,7 +11,7 @@ import DataGrid from "@/components/module/DataGrid"; import SearchForm from "@/components/module/SearchForm"; import type { ColumnInfo } from "@/components/type/DataGrid.type"; import type { SearchFormValues } from "@/components/type/SearchForm.type"; -import { getST00020003Config, getST00020005Config,SewagePipeColumnInfoListTot } from "@/components/util/column/total/SewagePipeTotColumn"; +import { getST00020003Config, SewagePipeColumnInfoListTot } from "@/components/util/column/total/SewagePipeTotColumn"; import { toGridRows } from "@/components/util/grid/gridFunction"; const firstTabKey = SewagePipeColumnInfoListTot[0]?.tabKey ?? "ST00020001"; @@ -205,12 +205,10 @@ const SewagePipeTot = () => { {columnInfo.map((info) => { const tabKey = info.tabKey; - // ★ [동적 처리] ST00020003·ST00020005는 함수를 통해 컬럼 정보를 실시간으로 생성 + // ★ [동적 처리] ST00020003은 함수를 통해 컬럼 정보를 실시간으로 생성 const currentYear = lastSearchedValuesRef.current?.year || new Date().getFullYear(); const finalTabConfig = - tabKey === "ST00020003" ? getST00020003Config(currentYear) : - tabKey === "ST00020005" ? getST00020005Config(currentYear) : - info; + tabKey === "ST00020003" ? getST00020003Config(currentYear) : info; if (!finalTabConfig.columns || !finalTabConfig.columnLayout) { return null; diff --git a/apps/st/src/components/statistics/verification/GeneralVerificationManagement.tsx b/apps/st/src/components/statistics/verification/GeneralVerificationManagement.tsx index 65fc5b340..5873b421d 100644 --- a/apps/st/src/components/statistics/verification/GeneralVerificationManagement.tsx +++ b/apps/st/src/components/statistics/verification/GeneralVerificationManagement.tsx @@ -9,7 +9,12 @@ import { useAlertStore } from "@/shared/lib"; import { NoData } from "@/shared/ui/no-data"; import { CodeSelectWithAll } from "@/entities/code"; import { generalverificationApiService } from "@/entities/statistics/api/general-verification-service"; +import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service"; import type { GeneralverificationList } from "@/entities/statistics/model/general-verification-interface"; +import { + getInputPeriodVerificationManageBlockedMessage, + isInputPeriodCurrent, +} from "@/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface"; import { Button, DataTable, @@ -47,6 +52,10 @@ const GeneralVerificationManagement = () => { const [isExporting, setIsExporting] = useState(false); const [selectedVrfcRow, setSelectedVrfcRow] = useState(null); const [showRegistForm, setShowRegistForm] = useState(false); + const [inputPeriodBlocked, setInputPeriodBlocked] = useState(false); + const [inputPeriodBlockedMessage, setInputPeriodBlockedMessage] = useState< + string | null + >(null); const { setMessage: alert } = useAlertStore((state) => state); @@ -91,8 +100,18 @@ const GeneralVerificationManagement = () => { }; const columns = useMemo( - () => getGeneralVerificationColumns(() => handleSearch()), - [searchValues.statsCd, searchValues.vrfcClsfCd, searchValues.useYn], + () => + getGeneralVerificationColumns(() => handleSearch(), { + mutationBlocked: inputPeriodBlocked, + blockedMessage: inputPeriodBlockedMessage, + }), + [ + searchValues.statsCd, + searchValues.vrfcClsfCd, + searchValues.useYn, + inputPeriodBlocked, + inputPeriodBlockedMessage, + ], ); const table = useReactTable({ @@ -162,6 +181,24 @@ const GeneralVerificationManagement = () => { useEffect(() => { void handleSearch(); + void (async () => { + try { + const statsYr = String(new Date().getFullYear() - 1); + const response = + await statisticsInputSewSupplyRateApi.checkInputPeriod(statsYr); + if (response.status !== "success") return; + const blocked = isInputPeriodCurrent(response.data); + setInputPeriodBlocked(blocked); + setInputPeriodBlockedMessage( + blocked + ? getInputPeriodVerificationManageBlockedMessage(response.data) + : null, + ); + } catch { + setInputPeriodBlocked(false); + setInputPeriodBlockedMessage(null); + } + })(); }, []); return ( @@ -263,13 +300,25 @@ const GeneralVerificationManagement = () => { 내보내기 - void handleSearch()} - > - - + {inputPeriodBlocked ? ( + + + + ) : ( + void handleSearch()} + > + + + )}
@@ -294,7 +343,11 @@ const GeneralVerificationManagement = () => { )}
- + ); diff --git a/apps/st/src/components/statistics/verification/generalVerification/DetailComponent.tsx b/apps/st/src/components/statistics/verification/generalVerification/DetailComponent.tsx index 4f0d3781b..494ae6ee7 100644 --- a/apps/st/src/components/statistics/verification/generalVerification/DetailComponent.tsx +++ b/apps/st/src/components/statistics/verification/generalVerification/DetailComponent.tsx @@ -391,9 +391,15 @@ const buildRuleBlocksFromFormulas = ( interface DetailComponentProps { selectedVrfcRow: number | null; + mutationBlocked?: boolean; + blockedMessage?: string | null; } -const DetailComponent = ({ selectedVrfcRow }: DetailComponentProps) => { +const DetailComponent = ({ + selectedVrfcRow, + mutationBlocked = false, + blockedMessage = null, +}: DetailComponentProps) => { const [detailInfo, setDetailInfo] = useState(null); /** 수식 / 조건·논리 연산자를 순서대로 담는 UI 블록 (서로 강제 교차하지 않음) */ const [ruleBlocks, setRuleBlocks] = useState([ @@ -487,6 +493,13 @@ const DetailComponent = ({ selectedVrfcRow }: DetailComponentProps) => { }; const handleSaveClick = async () => { + if (mutationBlocked) { + alert( + blockedMessage ?? + "입력기간에는 검증항목을 등록하거나 수정할 수 없습니다.", + ); + return; + } const trgtStatsCd = detailInfo?.commonInfo.trgtStatsCd; if (!trgtStatsCd) { alert("대상 통계항목(trgtStatsCd) 정보가 없습니다."); @@ -623,6 +636,13 @@ const DetailComponent = ({ selectedVrfcRow }: DetailComponentProps) => { formula?: VerifyDetailResponseDto | null, blockId?: string, ) => { + if (mutationBlocked) { + alert( + blockedMessage ?? + "입력기간에는 검증항목을 등록하거나 수정할 수 없습니다.", + ); + return; + } setSelectedFormula(formula ?? null); setSelectedFormulaBlockId(blockId ?? null); setShowFomulaDialog(true); @@ -671,6 +691,13 @@ const DetailComponent = ({ selectedVrfcRow }: DetailComponentProps) => { }; const handleResetClick = async () => { + if (mutationBlocked) { + alert( + blockedMessage ?? + "입력기간에는 검증항목을 등록하거나 수정할 수 없습니다.", + ); + return; + } const currentSignature = JSON.stringify( normalizeFormulaListForCompare(formulaList, groupByFlags), ); @@ -689,6 +716,13 @@ const DetailComponent = ({ selectedVrfcRow }: DetailComponentProps) => { }; const handleAddClause = () => { + if (mutationBlocked) { + alert( + blockedMessage ?? + "입력기간에는 검증항목을 등록하거나 수정할 수 없습니다.", + ); + return; + } setRuleBlocks((prev) => [ ...prev, { @@ -702,6 +736,13 @@ const DetailComponent = ({ selectedVrfcRow }: DetailComponentProps) => { /** 항상 목록 맨 뒤(마지막 수식 뒤 포함)에 조건·논리 연산자 Select 추가 */ const handleAddConnector = () => { + if (mutationBlocked) { + alert( + blockedMessage ?? + "입력기간에는 검증항목을 등록하거나 수정할 수 없습니다.", + ); + return; + } if (connectorOperators.length === 0) { alert("조건·논리 연산자 목록을 불러오지 못했습니다."); return; @@ -720,6 +761,13 @@ const DetailComponent = ({ selectedVrfcRow }: DetailComponentProps) => { }; const handleRemoveBlock = (blockId: string) => { + if (mutationBlocked) { + alert( + blockedMessage ?? + "입력기간에는 검증항목을 등록하거나 수정할 수 없습니다.", + ); + return; + } setRuleBlocks((prev) => { const next = prev.filter((b) => b.id !== blockId); if (next.some((b) => b.kind === "formula")) return next; @@ -831,6 +879,7 @@ const DetailComponent = ({ selectedVrfcRow }: DetailComponentProps) => {
onGroupByChange?.(e.target.checked)} /> group by diff --git a/apps/st/src/components/statistics/verification/generalVerification/OperatorsComponents.tsx b/apps/st/src/components/statistics/verification/generalVerification/OperatorsComponents.tsx index fc93e698f..3ea75df1c 100644 --- a/apps/st/src/components/statistics/verification/generalVerification/OperatorsComponents.tsx +++ b/apps/st/src/components/statistics/verification/generalVerification/OperatorsComponents.tsx @@ -26,13 +26,15 @@ interface OperatorsComponentsProps { onValueChange?: (value: string) => void; placeholder?: string; opertSeCd?: string; + disabled?: boolean; } const OperatorsComponents = ({ cmprOpert, onValueChange, placeholder = "연산자 없음", - opertSeCd = "opertSeCd=CMPR" + opertSeCd = "opertSeCd=CMPR", + disabled = false, }: OperatorsComponentsProps) => { const [operators, setOperators] = useState([]); const [localValue, setLocalValue] = useState(cmprOpert ?? ""); @@ -75,6 +77,7 @@ const OperatorsComponents = ({ return ( @@ -416,6 +430,7 @@ const RegistDialog = memo( placeholder="소수점자리수를 입력해주세요" type="number" min={0} + disabled={editBlocked} />

@@ -443,7 +458,7 @@ const RegistDialog = memo(