diff --git a/apps/st/Dockerfile b/apps/st/Dockerfile new file mode 100644 index 000000000..1b0a9cfe0 --- /dev/null +++ b/apps/st/Dockerfile @@ -0,0 +1,28 @@ +FROM node:20-alpine + +# pnpm 설치 +RUN corepack enable && corepack prepare pnpm@8.15.5 --activate + +WORKDIR /app + +# 모든 소스 복사 +COPY . . + +# .env.production 파일 생성 +RUN mkdir -p /app/apps/st && \ + echo "NODE_ENV=production" > /app/apps/st/.env.production && \ + echo "PORT=3000" >> /app/apps/st/.env.production && \ + echo "NEXT_PUBLIC_PORT=3000" >> /app/apps/st/.env.production && \ + echo "SERVER_API_URL=http://dev.onasys.co.kr:8000" >> /app/apps/st/.env.production && \ + echo "NEXT_PUBLIC_PROXY_HOST=https://st.apps.rsonesoft.com" >> /app/apps/st/.env.production && \ + echo "NEXT_PUBLIC_TINY_API_KEY=t9nc4z6inquvvd5pq1vea8wcp7lb01qmqseh6egms9vpaju2" >> /app/apps/st/.env.production && \ + echo "NEXT_PUBLIC_ST_SERVICE_URL=https://apigateway.apps.rsonesoft.com" >> /app/apps/st/.env.production && \ + echo "NEXT_PUBLIC_ST_REALGRID_KEY=upVcPE+wPOmtLjqyBIh9RkM/nBOseBrflwxYpzGZyYnkTzf7Gmn/c+YNYZY36ZjDHoLUQjrb+Zx6JscIKXc6ti45WUEqxvh/kkzVSHLUHquykNuBw5QDg+AQvETEhgujkdwMl8bfXmKFzr6UT9cAmQ==" >> /app/apps/st/.env.production && \ + echo "NEXT_PUBLIC_SITE_ID=ST" >> /app/apps/st/.env.production + +RUN pnpm install --filter=st... +RUN pnpm build --filter=st... + +EXPOSE 3000 + +CMD ["sh", "-c", "pnpm --filter st start & wait"] \ No newline at end of file diff --git a/apps/st/src/components/module/SidoSggFacilityNameSearchForm.tsx b/apps/st/src/components/module/SidoSggFacilityNameSearchForm.tsx index a6b13b323..d0de96c69 100644 --- a/apps/st/src/components/module/SidoSggFacilityNameSearchForm.tsx +++ b/apps/st/src/components/module/SidoSggFacilityNameSearchForm.tsx @@ -695,20 +695,6 @@ const SidoSggFacilityNameSearchForm = ({ )}
-
-

- 처리시설 정보 -

- -

@@ -726,6 +712,20 @@ const SidoSggFacilityNameSearchForm = ({ // compactGridHeightClass="h-[min(40vh,28rem)] min-h-[16rem]" />

+
+

+ 처리시설 정보 +

+ +
); diff --git a/apps/st/src/components/statistics/input/ExcretaTreatmentFacilityInp.tsx b/apps/st/src/components/statistics/input/ExcretaTreatmentFacilityInp.tsx index 912993caf..034694ca2 100644 --- a/apps/st/src/components/statistics/input/ExcretaTreatmentFacilityInp.tsx +++ b/apps/st/src/components/statistics/input/ExcretaTreatmentFacilityInp.tsx @@ -16,6 +16,7 @@ import { useAlertStore, useGlobalProgressStore, useStatisticsInputToolbarGroupGa import { STATISTICS_INPUT_URL_PATH } from "@/shared/lib/stats-cd-input-navigation"; import { useStatisticsInputPendingNavigation } from "@/shared/lib/use-statistics-input-pending-navigation"; import { ConfirmDialog } from "@/shared/ui/confirm-dialog"; +import { filterSggOptionsBySearchGugun } from "@/components/util/input/filter-sgg-options-by-search"; import { nullableTrimmedString } from "@/components/util/input/nullableString"; import { statisticsInputExcretaTreatmentFacilityApi } from "@/entities/statistics/api/input/statistics-input-excreta-treatment-facility-service"; import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service"; @@ -144,8 +145,7 @@ function computeTabToolbarSnapshot( (hasRowData || treatAsSearched) && (showSaveInToolbar || showEnterableToolbarButtons || - showSubmittedInInputPeriodToolbar || - (isSubmitted && isAdminInfo)); + showSubmittedInInputPeriodToolbar); return { showSaveInToolbar, showEnterableToolbarButtons, showActionToolbarCard }; } @@ -444,7 +444,11 @@ const ExcretaTreatmentFacilityInp = () => { return { ...col, editable: false as const }; } if (col.fieldName === "sggNm" && enterable) { - return buildSggNmColumn(col, true, sggOptions); + return buildSggNmColumn( + col, + true, + filterSggOptionsBySearchGugun(sggOptions, lastSearchedValues?.gugun), + ); } return col; }) @@ -457,7 +461,7 @@ const ExcretaTreatmentFacilityInp = () => { columns, columnLayout: ExcretaTreatFactInpColumn.columnLayout ?? [], }; - }, [statusInfo, inputPeriodEnterable, isAdminInfo, sggOptions, columnGuidesByEngCol]); + }, [statusInfo, inputPeriodEnterable, isAdminInfo, sggOptions, lastSearchedValues?.gugun, columnGuidesByEngCol]); const canEditGrid = (computeTabEnterable(statusInfo, inputPeriodEnterable) || isAdminInfo) && inputPeriodEnterable; @@ -1044,7 +1048,7 @@ const ExcretaTreatmentFacilityInp = () => { {submitOk && } )} - {statusInfo?.lclgvSbmsnSttsCd === "2" && submitOk && ( + {statusInfo?.lclgvSbmsnSttsCd === "2" && submitOk && inputPeriodEnterable && ( )} {showSaveInToolbar && } diff --git a/apps/st/src/components/statistics/input/PrivateSewageFacilityInp.tsx b/apps/st/src/components/statistics/input/PrivateSewageFacilityInp.tsx index ee95052a1..dc028aa30 100644 --- a/apps/st/src/components/statistics/input/PrivateSewageFacilityInp.tsx +++ b/apps/st/src/components/statistics/input/PrivateSewageFacilityInp.tsx @@ -161,8 +161,7 @@ function computeTabToolbarSnapshot( (hasRowData || treatAsSearched) && (showSaveInToolbar || showEnterableToolbarButtons || - showSubmittedInInputPeriodToolbar || - (isSubmitted && isAdminInfo)); + showSubmittedInInputPeriodToolbar); return { showSaveInToolbar, showEnterableToolbarButtons, showActionToolbarCard }; } @@ -1200,7 +1199,7 @@ const PrivateSewageFacilityInp = () => { {submitOk && } )} - {activeTabStatus?.lclgvSbmsnSttsCd === "2" && submitOk && ( + {activeTabStatus?.lclgvSbmsnSttsCd === "2" && submitOk && inputPeriodEnterable && ( )} {showSaveInToolbar && } diff --git a/apps/st/src/components/statistics/input/PublicSewageFacilityInp.tsx b/apps/st/src/components/statistics/input/PublicSewageFacilityInp.tsx index cac3212cc..a99d8a3f8 100644 --- a/apps/st/src/components/statistics/input/PublicSewageFacilityInp.tsx +++ b/apps/st/src/components/statistics/input/PublicSewageFacilityInp.tsx @@ -121,8 +121,7 @@ function computeTabToolbarSnapshot( (hasRowData || treatAsSearched) && (showSaveInToolbar || showEnterableToolbarButtons || - showSubmittedInInputPeriodToolbar || - (isSubmitted && isAdminInfo)); + showSubmittedInInputPeriodToolbar); return { showSaveInToolbar, showEnterableToolbarButtons, showActionToolbarCard }; } @@ -1336,7 +1335,7 @@ const PublicSewageFacilityInp = () => { {submitOk && } )} - {!isMainFacilityTab && activeTabStatus?.lclgvSbmsnSttsCd === '2' && submitOk && ( + {!isMainFacilityTab && activeTabStatus?.lclgvSbmsnSttsCd === '2' && submitOk && inputPeriodEnterable && ( )} {showSaveInToolbar && } diff --git a/apps/st/src/components/statistics/input/PumpingStationInp.tsx b/apps/st/src/components/statistics/input/PumpingStationInp.tsx index 412318321..70cc60b61 100644 --- a/apps/st/src/components/statistics/input/PumpingStationInp.tsx +++ b/apps/st/src/components/statistics/input/PumpingStationInp.tsx @@ -16,6 +16,7 @@ import { useAlertStore, useGlobalProgressStore, useStatisticsInputToolbarGroupGa import { STATISTICS_INPUT_URL_PATH } from "@/shared/lib/stats-cd-input-navigation"; import { useStatisticsInputPendingNavigation } from "@/shared/lib/use-statistics-input-pending-navigation"; import { ConfirmDialog } from "@/shared/ui/confirm-dialog"; +import { filterSggOptionsBySearchGugun } from "@/components/util/input/filter-sgg-options-by-search"; import { nullableTrimmedString } from "@/components/util/input/nullableString"; import { statisticsInputPumpingStationApi } from "@/entities/statistics/api/input/statistics-input-pumping-station-service"; import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service"; @@ -144,8 +145,7 @@ function computeTabToolbarSnapshot( (hasRowData || treatAsSearched) && (showSaveInToolbar || showEnterableToolbarButtons || - showSubmittedInInputPeriodToolbar || - (isSubmitted && isAdminInfo)); + showSubmittedInInputPeriodToolbar); return { showSaveInToolbar, showEnterableToolbarButtons, showActionToolbarCard }; } @@ -438,7 +438,11 @@ const PumpingStationInp = () => { return { ...col, editable: false as const }; } if (col.fieldName === "sggNm" && enterable) { - return buildSggNmColumn(col, true, sggOptions); + return buildSggNmColumn( + col, + true, + filterSggOptionsBySearchGugun(sggOptions, lastSearchedValues?.gugun), + ); } return col; }) @@ -451,7 +455,7 @@ const PumpingStationInp = () => { columns, columnLayout: PumpingStationInpColumn.columnLayout ?? [], }; - }, [statusInfo, inputPeriodEnterable, isAdminInfo, sggOptions, columnGuidesByEngCol]); + }, [statusInfo, inputPeriodEnterable, isAdminInfo, sggOptions, lastSearchedValues?.gugun, columnGuidesByEngCol]); const canEditGrid = (computeTabEnterable(statusInfo, inputPeriodEnterable) || isAdminInfo) && inputPeriodEnterable; @@ -1027,7 +1031,7 @@ const PumpingStationInp = () => { {submitOk && } )} - {statusInfo?.lclgvSbmsnSttsCd === "2" && submitOk && ( + {statusInfo?.lclgvSbmsnSttsCd === "2" && submitOk && inputPeriodEnterable && ( )} {showSaveInToolbar && } diff --git a/apps/st/src/components/statistics/input/SewageExcretaRelatedInp.tsx b/apps/st/src/components/statistics/input/SewageExcretaRelatedInp.tsx index 7a325ee3c..f5daa4888 100644 --- a/apps/st/src/components/statistics/input/SewageExcretaRelatedInp.tsx +++ b/apps/st/src/components/statistics/input/SewageExcretaRelatedInp.tsx @@ -9,6 +9,7 @@ import { useAlertStore, useGlobalProgressStore, useStatisticsInputToolbarGroupGa import { STATISTICS_INPUT_URL_PATH } from "@/shared/lib/stats-cd-input-navigation"; import { useStatisticsInputPendingNavigation } from "@/shared/lib/use-statistics-input-pending-navigation"; import { ConfirmDialog } from "@/shared/ui/confirm-dialog"; +import { filterSggOptionsBySearchGugun } from "@/components/util/input/filter-sgg-options-by-search"; import { nullableTrimmedString } from "@/components/util/input/nullableString"; import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service"; import { statisticsInputSewageExcretaRelatedApi } from "@/entities/statistics/api/input/statistics-input-sewage-excreta-related-service"; @@ -208,8 +209,7 @@ function computeTabToolbarSnapshot( (hasRowData || treatAsSearched) && (showSaveInToolbar || showEnterableToolbarButtons || - showSubmittedInInputPeriodToolbar || - (isSubmitted && isAdminInfo)); + showSubmittedInInputPeriodToolbar); return { showSaveInToolbar, showEnterableToolbarButtons, showActionToolbarCard }; } @@ -1887,7 +1887,11 @@ const SewageExcretaRelatedInp = () => { SGG_NM_DROPDOWN_TAB_KEYS.has(tabKey) && col.fieldName === "sggNm" ) { - next = buildSggNmColumn(col, canEdit, sggOptions); + next = buildSggNmColumn( + col, + canEdit, + filterSggOptionsBySearchGugun(sggOptions, lastSearchedValues?.gugun), + ); } else if (col.fieldName === "sggNm") { next = { ...col, editable: false as const, styleName: "rg-cell-readonly" }; } @@ -1900,7 +1904,7 @@ const SewageExcretaRelatedInp = () => { }); } return map; - }, [tabStatusInfoMap, inputPeriodEnterable, isAdminInfo, columnGuidesByTab, sggOptions]); + }, [tabStatusInfoMap, inputPeriodEnterable, isAdminInfo, columnGuidesByTab, sggOptions, lastSearchedValues?.gugun]); const publicInstitutionArticleCellStyleCallback = useCallback( ({ fieldName, row }) => { @@ -2023,7 +2027,7 @@ const SewageExcretaRelatedInp = () => { {submitOk && } )} - {activeTabStatus?.lclgvSbmsnSttsCd === "2" && submitOk && ( + {activeTabStatus?.lclgvSbmsnSttsCd === "2" && submitOk && inputPeriodEnterable && ( )} {showSaveInToolbar && } diff --git a/apps/st/src/components/statistics/input/SewageExcretaSlurgeInp.tsx b/apps/st/src/components/statistics/input/SewageExcretaSlurgeInp.tsx index 4ea9895f1..72fc2740e 100644 --- a/apps/st/src/components/statistics/input/SewageExcretaSlurgeInp.tsx +++ b/apps/st/src/components/statistics/input/SewageExcretaSlurgeInp.tsx @@ -17,6 +17,7 @@ import { useAlertStore, useGlobalProgressStore, useStatisticsInputToolbarGroupGa import { STATISTICS_INPUT_URL_PATH } from "@/shared/lib/stats-cd-input-navigation"; import { useStatisticsInputPendingNavigation } from "@/shared/lib/use-statistics-input-pending-navigation"; import { ConfirmDialog } from "@/shared/ui/confirm-dialog"; +import { filterSggOptionsBySearchGugun } from "@/components/util/input/filter-sgg-options-by-search"; import { nullableTrimmedString } from "@/components/util/input/nullableString"; import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service"; import { statisticsInputSewageExcretaSlurgeApi } from "@/entities/statistics/api/input/statistics-input-sewage-excreta-slurge-service"; @@ -60,6 +61,7 @@ import LastYearDataButton from "@/components/button/LastYearDataButton"; import NotApplicableCheckButton from "@/components/button/NotApplicableCheckButton"; import SaveButton from "@/components/button/SaveButton"; import SubmitButton from "@/components/button/SumitButton"; +import UpdateOperateDataButton from "@/components/button/UpdateOperateDataButton"; import VerificationResultButton from "@/components/button/VerificationResultButton"; import DataGrid from "@/components/module/DataGrid"; import { openVerificationResultDialogIfNeeded } from "@/components/module/post-submit-verification-results"; @@ -184,10 +186,10 @@ function mapListToGridRows { noApplicable || !isSewageSlurgeFacTab ? [] : rowsForSubmit.map((row) => - buildSewageSlurgeProcessingFacStatusSaveItem(row, list), - ); + buildSewageSlurgeProcessingFacStatusSaveItem(row, list), + ); const excretaSlurgeSubmitList = noApplicable || !isExcretaSlurgeTab ? [] : rowsForSubmit.map((row) => - buildExcretaSlurgeProcessingStatusSaveItem(row, list), - ); + buildExcretaSlurgeProcessingStatusSaveItem(row, list), + ); const sewageSlurgeFacDeleteList = isSewageSlurgeFacTab ? (deleteListByTab.get(tabKey) ?? []) - .filter((row) => isPersistedArticleRowForTab(tabKey, row)) - .map((row) => buildSewageSlurgeProcessingFacStatusSaveItem(row, list)) + .filter((row) => isPersistedArticleRowForTab(tabKey, row)) + .map((row) => buildSewageSlurgeProcessingFacStatusSaveItem(row, list)) : []; if ( @@ -1373,10 +1374,10 @@ const SewageExcretaSlurgeInp = () => { (isDigestorTab ? SEWAGE_EXCRETA_DIGESTOR_OPERATING_STATS_CD : isSewageSlurgeFacTab - ? SEWAGE_EXCRETA_SEWAGE_SLURGE_FAC_STATUS_STATS_CD - : isExcretaSlurgeTab - ? SEWAGE_EXCRETA_EXCRETA_SLURGE_PROCESSING_STATS_CD - : SEWAGE_EXCRETA_SLURGE_PROCESSING_FAC_STATUS_STATS_CD); + ? SEWAGE_EXCRETA_SEWAGE_SLURGE_FAC_STATUS_STATS_CD + : isExcretaSlurgeTab + ? SEWAGE_EXCRETA_EXCRETA_SLURGE_PROCESSING_STATS_CD + : SEWAGE_EXCRETA_SLURGE_PROCESSING_FAC_STATUS_STATS_CD); const verificationQuery = { ...toInputSearchRegion(sidoListRef.current, lastSearchedValues), @@ -1428,32 +1429,32 @@ const SewageExcretaSlurgeInp = () => { setGlobalProgressLabel("일반 검증 진행 중..."); const response = isSlurgeFacTab ? await statisticsInputSewageExcretaSlurgeApi.submitSlurgeProcessingFacStatus({ - ...submitRequestBase, - userUuid: userInfo.userUnqId, - submitList: slurgeSubmitList, - }) + ...submitRequestBase, + userUuid: userInfo.userUnqId, + submitList: slurgeSubmitList, + }) : isDigestorTab - ? await statisticsInputSewageExcretaSlurgeApi.submitDigestorOperatingStatus({ + ? await statisticsInputSewageExcretaSlurgeApi.submitDigestorOperatingStatus({ ...submitRequestBase, userUuid: userInfo.userUnqId, submitList: digestorSubmitList, }) - : isSewageSlurgeFacTab - ? await statisticsInputSewageExcretaSlurgeApi.submitSewageSlurgeProcessingFacStatus( - { - ...submitRequestBase, - userUuid: userInfo.userUnqId, - submitList: sewageSlurgeFacSubmitList, - deleteList: sewageSlurgeFacDeleteList, - }, - ) - : await statisticsInputSewageExcretaSlurgeApi.submitExcretaSlurgeProcessingStatus( - { - ...submitRequestBase, - userUuid: userInfo.userUnqId, - submitList: excretaSlurgeSubmitList, - }, - ); + : isSewageSlurgeFacTab + ? await statisticsInputSewageExcretaSlurgeApi.submitSewageSlurgeProcessingFacStatus( + { + ...submitRequestBase, + userUuid: userInfo.userUnqId, + submitList: sewageSlurgeFacSubmitList, + deleteList: sewageSlurgeFacDeleteList, + }, + ) + : await statisticsInputSewageExcretaSlurgeApi.submitExcretaSlurgeProcessingStatus( + { + ...submitRequestBase, + userUuid: userInfo.userUnqId, + submitList: excretaSlurgeSubmitList, + }, + ); if (response.status !== "success") { alert(response.message ?? "데이터 제출 중 오류가 발생했습니다."); @@ -1533,6 +1534,61 @@ const SewageExcretaSlurgeInp = () => { } }; + const updateOperateDataButtonFunc = () => { + void (async () => { + if (!lastSearchedValues) { + alert("먼저 조회를 진행해주세요."); + return; + } + if (!(await confirm("자체발생량·함수율·자체 1차 처리량이 운영 데이터로 덮어씁니다."))) { + return; + } + + try { + showGlobalProgress({ label: "운영 데이터 업데이트 중...", progress: 0 }); + const userInfo = await getUserInfo(); + const request = { + statsYr: lastSearchedValues.year ?? "", + ctpvNm: lastSearchedValues.sido ?? "", + ...toInputSearchRegion(sidoListRef.current, lastSearchedValues), + userUuid: userInfo.userUnqId, + }; + + const response = + await statisticsInputSewageExcretaSlurgeApi.updateSlurgeProcessingFacStatusOperationData( + request, + ); + if (response.status !== "success") { + alert( + response.message || + "운영 데이터 업데이트 중 오류가 발생했습니다.", + ); + return; + } + + setGlobalProgress(50); + const tabKey = SlurgeProcessingFacStatusInpColumn.tabKey; + const param = + searchParamRef.current ?? + buildSewageExcretaSlurgeSearchParam(lastSearchedValues); + await loadActiveTabData(tabKey, param, lastSearchedValues, true, false); + setGlobalProgress(100); + alert("운영 데이터가 업데이트되었습니다."); + } catch (error) { + const message = + error && + typeof error === "object" && + "response" in error + ? (error as { response?: { data?: { message?: string } } }) + .response?.data?.message + : undefined; + alert(message || "운영 데이터 업데이트 중 오류가 발생했습니다."); + } finally { + hideGlobalProgress(); + } + })(); + }; + const cnacelSubmitFunc = () => { void (async () => { try { @@ -1644,8 +1700,8 @@ const SewageExcretaSlurgeInp = () => { const saveList = noApplicable ? [] : rowsForSave.map((row) => - buildSlurgeProcessingFacStatusSaveItem(row, list), - ); + buildSlurgeProcessingFacStatusSaveItem(row, list), + ); if (!noApplicable && saveList.length === 0 && buildSubmitOkForToolbar(searchContextByTab.get(tabKey) ?? lastSearchedValues)) { alert("해당사항 없음을 체크해주세요."); @@ -1670,8 +1726,8 @@ const SewageExcretaSlurgeInp = () => { const saveList = noApplicable ? [] : rowsForSave.map((row) => - buildDigestorOperatingStatusSaveItem(row, list), - ); + buildDigestorOperatingStatusSaveItem(row, list), + ); if (!noApplicable && saveList.length === 0 && buildSubmitOkForToolbar(searchContextByTab.get(tabKey) ?? lastSearchedValues)) { alert("해당사항 없음을 체크해주세요."); @@ -1693,8 +1749,8 @@ const SewageExcretaSlurgeInp = () => { const saveList = noApplicable ? [] : rowsForSave.map((row) => - buildSewageSlurgeProcessingFacStatusSaveItem(row, list), - ); + buildSewageSlurgeProcessingFacStatusSaveItem(row, list), + ); const deleteList = (deleteListByTab.get(tabKey) ?? []) .filter((row) => isPersistedArticleRowForTab(tabKey, row)) .map((row) => buildSewageSlurgeProcessingFacStatusSaveItem(row, list)); @@ -1723,8 +1779,8 @@ const SewageExcretaSlurgeInp = () => { const saveList = noApplicable ? [] : rowsForSave.map((row) => - buildExcretaSlurgeProcessingStatusSaveItem(row, list), - ); + buildExcretaSlurgeProcessingStatusSaveItem(row, list), + ); if (!noApplicable && saveList.length === 0 && buildSubmitOkForToolbar(searchContextByTab.get(tabKey) ?? lastSearchedValues)) { alert("해당사항 없음을 체크해주세요."); @@ -1776,17 +1832,17 @@ const SewageExcretaSlurgeInp = () => { const getCheckedItemIndexesFromGrid = (rowCount: number): number[] => { const gridView = getGridRef.current?.gridView as | { - getCheckedItems?: () => number[]; - getCheckedRows?: () => number[]; - } + getCheckedItems?: () => number[]; + getCheckedRows?: () => number[]; + } | undefined; const checked = (typeof gridView?.getCheckedItems === "function" ? gridView.getCheckedItems() : typeof gridView?.getCheckedRows === "function" - ? gridView.getCheckedRows() - : []) ?? []; + ? gridView.getCheckedRows() + : []) ?? []; return checked.filter( (idx) => Number.isInteger(idx) && idx >= 0 && idx < rowCount, @@ -1858,10 +1914,10 @@ const SewageExcretaSlurgeInp = () => { checkedIndexes.length > 0 ? new Set(checkedIndexes) : new Set( - currentRows - .map((row, idx) => (isCheckedRow(row) ? idx : -1)) - .filter((idx) => idx >= 0), - ); + currentRows + .map((row, idx) => (isCheckedRow(row) ? idx : -1)) + .filter((idx) => idx >= 0), + ); const removedRows = currentRows.filter((_, idx) => checkedIndexSet.has(idx)); const nextRows = currentRows.filter((_, idx) => !checkedIndexSet.has(idx)); @@ -1920,7 +1976,11 @@ const SewageExcretaSlurgeInp = () => { SGG_NM_DROPDOWN_TAB_KEYS.has(tabKey) && col.fieldName === "sggNm" ) { - next = buildSggNmColumn(col, canEdit, sggOptions); + next = buildSggNmColumn( + col, + canEdit, + filterSggOptionsBySearchGugun(sggOptions, lastSearchedValues?.gugun), + ); } else if (col.fieldName === "sggNm") { next = { ...col, editable: false as const, styleName: "rg-cell-readonly" }; } @@ -2080,8 +2140,8 @@ const SewageExcretaSlurgeInp = () => { onValuesChange={setSearchValues} /> {showActionToolbarCard && ( -
-
+
+
{ void lastYearDataFunc()} /> - {submitOk && } + {activeTab === SEWAGE_EXCRETA_SLURGE_PROCESSING_FAC_STATUS_STATS_CD && ( + + )} + {submitOk && } )} - {activeTabStatus?.lclgvSbmsnSttsCd === "2" && submitOk && ( + {activeTabStatus?.lclgvSbmsnSttsCd === "2" && submitOk && inputPeriodEnterable && ( )} {showSaveInToolbar && } -
-
+
+
)} {showSecondaryToolbarCard && ( -
-
+
+
{showNotApplicableForActiveTab && ( { )} {showArticleEditButtons && ( <> - - + + )} -
-
+
+
)} {isLoading && (
diff --git a/apps/st/src/components/statistics/input/SewagePipeInp.tsx b/apps/st/src/components/statistics/input/SewagePipeInp.tsx index 3aced129c..b7cf15409 100644 --- a/apps/st/src/components/statistics/input/SewagePipeInp.tsx +++ b/apps/st/src/components/statistics/input/SewagePipeInp.tsx @@ -453,8 +453,7 @@ function computeTabToolbarSnapshot( (hasRowData || treatAsSearched) && (showSaveInToolbar || showEnterableToolbarButtons || - showSubmittedInInputPeriodToolbar || - (isSubmitted && isAdminInfo)); + showSubmittedInInputPeriodToolbar); return { showSaveInToolbar, showEnterableToolbarButtons, showActionToolbarCard }; } @@ -2062,7 +2061,7 @@ const SewagePipeInp = () => { {submitOk && void submitFunc(false)} />} )} - {activeTabStatus?.lclgvSbmsnSttsCd === "2" && submitOk && ( + {activeTabStatus?.lclgvSbmsnSttsCd === "2" && submitOk && inputPeriodEnterable && ( )} {showSaveInToolbar && } diff --git a/apps/st/src/components/statistics/input/SewagePipeMaintainInp.tsx b/apps/st/src/components/statistics/input/SewagePipeMaintainInp.tsx index e1235c14d..3a8f1e5be 100644 --- a/apps/st/src/components/statistics/input/SewagePipeMaintainInp.tsx +++ b/apps/st/src/components/statistics/input/SewagePipeMaintainInp.tsx @@ -156,8 +156,7 @@ function computeTabToolbarSnapshot( (hasRowData || treatAsSearched) && (showSaveInToolbar || showEnterableToolbarButtons || - showSubmittedInInputPeriodToolbar || - (isSubmitted && isAdminInfo)); + showSubmittedInInputPeriodToolbar); return { showSaveInToolbar, showEnterableToolbarButtons, showActionToolbarCard }; } @@ -1150,7 +1149,7 @@ const SewagePipeMaintainInp = () => { {submitOk && } )} - {activeTabStatus?.lclgvSbmsnSttsCd === "2" && submitOk && ( + {activeTabStatus?.lclgvSbmsnSttsCd === "2" && submitOk && inputPeriodEnterable && ( )} {showSaveInToolbar && } diff --git a/apps/st/src/components/statistics/input/SewageReservoirPumpInp.tsx b/apps/st/src/components/statistics/input/SewageReservoirPumpInp.tsx index 93d5f3db5..43bf143ce 100644 --- a/apps/st/src/components/statistics/input/SewageReservoirPumpInp.tsx +++ b/apps/st/src/components/statistics/input/SewageReservoirPumpInp.tsx @@ -17,6 +17,7 @@ import { useAlertStore, useGlobalProgressStore, useStatisticsInputToolbarGroupGa import { STATISTICS_INPUT_URL_PATH } from "@/shared/lib/stats-cd-input-navigation"; import { useStatisticsInputPendingNavigation } from "@/shared/lib/use-statistics-input-pending-navigation"; import { ConfirmDialog } from "@/shared/ui/confirm-dialog"; +import { filterSggOptionsBySearchGugun } from "@/components/util/input/filter-sgg-options-by-search"; import { nullableTrimmedString } from "@/components/util/input/nullableString"; import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service"; import { statisticsInputSewageReservoirPumpApi } from "@/entities/statistics/api/input/statistics-input-sewage-reservoir-pump-service"; @@ -176,8 +177,7 @@ function computeTabToolbarSnapshot( (hasRowData || treatAsSearched) && (showSaveInToolbar || showEnterableToolbarButtons || - showSubmittedInInputPeriodToolbar || - (isSubmitted && isAdminInfo)); + showSubmittedInInputPeriodToolbar); return { showSaveInToolbar, showEnterableToolbarButtons, showActionToolbarCard }; } @@ -1491,7 +1491,11 @@ const SewageReservoirPumpInp = () => { col.fieldName === "sggNm" && canEdit ) { - return buildSggNmColumn(col, true, sggOptions); + return buildSggNmColumn( + col, + true, + filterSggOptionsBySearchGugun(sggOptions, lastSearchedValues?.gugun), + ); } return col; }).map((col) => { @@ -1504,7 +1508,7 @@ const SewageReservoirPumpInp = () => { }); } return map; - }, [tabStatusInfoMap, inputPeriodEnterable, isAdminInfo, sggOptions, columnGuidesByTab]); + }, [tabStatusInfoMap, inputPeriodEnterable, isAdminInfo, sggOptions, lastSearchedValues?.gugun, columnGuidesByTab]); const verificationCellStyle = ({ fieldName, @@ -1583,7 +1587,7 @@ const SewageReservoirPumpInp = () => { {submitOk && } )} - {activeTabStatus?.lclgvSbmsnSttsCd === "2" && submitOk && ( + {activeTabStatus?.lclgvSbmsnSttsCd === "2" && submitOk && inputPeriodEnterable && ( )} {showSaveInToolbar && } diff --git a/apps/st/src/components/statistics/input/SewerageFinanceInp.tsx b/apps/st/src/components/statistics/input/SewerageFinanceInp.tsx index 5e71ec541..5787a52c8 100644 --- a/apps/st/src/components/statistics/input/SewerageFinanceInp.tsx +++ b/apps/st/src/components/statistics/input/SewerageFinanceInp.tsx @@ -160,8 +160,7 @@ function computeTabToolbarSnapshot( (hasRowData || treatAsSearched) && (showSaveInToolbar || showEnterableToolbarButtons || - showSubmittedInInputPeriodToolbar || - (isSubmitted && isAdminInfo)); + showSubmittedInInputPeriodToolbar); return { showSaveInToolbar, showEnterableToolbarButtons, showActionToolbarCard }; } @@ -1271,7 +1270,7 @@ const SewerageFinanceInp = () => { {submitOk && } )} - {activeTabStatus?.lclgvSbmsnSttsCd === "2" && submitOk && ( + {activeTabStatus?.lclgvSbmsnSttsCd === "2" && submitOk && inputPeriodEnterable && ( )} {showSaveInToolbar && } diff --git a/apps/st/src/components/statistics/input/SeweragePenetrationRateInp.tsx b/apps/st/src/components/statistics/input/SeweragePenetrationRateInp.tsx index d5f560a54..f5bd21308 100644 --- a/apps/st/src/components/statistics/input/SeweragePenetrationRateInp.tsx +++ b/apps/st/src/components/statistics/input/SeweragePenetrationRateInp.tsx @@ -815,8 +815,7 @@ const SeweragePenetrationRateInp = () => { toolbarGroupAllowed && (baseShowSaveInToolbar || baseShowEnterableToolbarButtons || - showSubmittedInInputPeriodToolbar || - (isSubmitted && isAdminInfo)); + showSubmittedInInputPeriodToolbar); return ( <> @@ -842,7 +841,7 @@ const SeweragePenetrationRateInp = () => { {submitOk && submitFunc(false)} />} )} - {statusInfo?.lclgvSbmsnSttsCd === '2' && submitOk && } + {statusInfo?.lclgvSbmsnSttsCd === '2' && submitOk && inputPeriodCurrent && } {showSaveInToolbar && }
diff --git a/apps/st/src/components/statistics/input/SewerageServiceLevelInp.tsx b/apps/st/src/components/statistics/input/SewerageServiceLevelInp.tsx index 2ebae634a..4d834fdfa 100644 --- a/apps/st/src/components/statistics/input/SewerageServiceLevelInp.tsx +++ b/apps/st/src/components/statistics/input/SewerageServiceLevelInp.tsx @@ -169,8 +169,7 @@ function computeTabToolbarSnapshot( (hasRowData || treatAsSearched) && (showSaveInToolbar || showEnterableToolbarButtons || - showSubmittedInInputPeriodToolbar || - (isSubmitted && isAdminInfo)); + showSubmittedInInputPeriodToolbar); return { showSaveInToolbar, showEnterableToolbarButtons, showActionToolbarCard }; } @@ -1202,7 +1201,7 @@ const SewerageServiceLevelInp = () => { {submitOk && } )} - {activeTabStatus?.lclgvSbmsnSttsCd === "2" && submitOk && ( + {activeTabStatus?.lclgvSbmsnSttsCd === "2" && submitOk && inputPeriodEnterable && ( )} {showSaveInToolbar && } diff --git a/apps/st/src/components/statistics/input/WaterReuseInp.tsx b/apps/st/src/components/statistics/input/WaterReuseInp.tsx index d631c6eba..ea1f7c881 100644 --- a/apps/st/src/components/statistics/input/WaterReuseInp.tsx +++ b/apps/st/src/components/statistics/input/WaterReuseInp.tsx @@ -17,6 +17,7 @@ import { useAlertStore, useGlobalProgressStore, useStatisticsInputToolbarGroupGa import { STATISTICS_INPUT_URL_PATH } from "@/shared/lib/stats-cd-input-navigation"; import { useStatisticsInputPendingNavigation } from "@/shared/lib/use-statistics-input-pending-navigation"; import { ConfirmDialog } from "@/shared/ui/confirm-dialog"; +import { filterSggOptionsBySearchGugun } from "@/components/util/input/filter-sgg-options-by-search"; import { nullableTrimmedString } from "@/components/util/input/nullableString"; import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service"; import { statisticsInputWaterReuseApi } from "@/entities/statistics/api/input/statistics-input-water-reuse-service"; @@ -208,8 +209,7 @@ function computeTabToolbarSnapshot( (hasRowData || treatAsSearched) && (showSaveInToolbar || showEnterableToolbarButtons || - showSubmittedInInputPeriodToolbar || - (isSubmitted && isAdminInfo)); + showSubmittedInInputPeriodToolbar); return { showSaveInToolbar, showEnterableToolbarButtons, showActionToolbarCard }; } @@ -1982,7 +1982,11 @@ const WaterReuseInp = () => { ARTICLE_EDIT_TAB_KEYS.has(tabKey) && col.fieldName === "sggNm" ) { - next = buildSggNmColumn(col, canEdit, sggOptions); + next = buildSggNmColumn( + col, + canEdit, + filterSggOptionsBySearchGugun(sggOptions, lastSearchedValues?.gugun), + ); } const guide = columnGuidesByTab[tabKey]?.[col.fieldName]?.trim(); return guide ? { ...next, tooltip: guide } : next; @@ -1993,7 +1997,7 @@ const WaterReuseInp = () => { }); } return map; - }, [tabStatusInfoMap, inputPeriodEnterable, isAdminInfo, columnGuidesByTab, sggOptions]); + }, [tabStatusInfoMap, inputPeriodEnterable, isAdminInfo, columnGuidesByTab, sggOptions, lastSearchedValues?.gugun]); const searchContextForToolbar = searchContextByTab.get(activeTab) ?? lastSearchedValues; const activeTabStatus = tabStatusInfoMap.get(activeTab) ?? null; @@ -2125,7 +2129,7 @@ const WaterReuseInp = () => { {submitOk && } )} - {activeTabStatus?.lclgvSbmsnSttsCd === "2" && submitOk && ( + {activeTabStatus?.lclgvSbmsnSttsCd === "2" && submitOk && inputPeriodEnterable && ( )} {showSaveInToolbar && } diff --git a/apps/st/src/components/util/input/filter-sgg-options-by-search.ts b/apps/st/src/components/util/input/filter-sgg-options-by-search.ts new file mode 100644 index 000000000..63a9780ac --- /dev/null +++ b/apps/st/src/components/util/input/filter-sgg-options-by-search.ts @@ -0,0 +1,13 @@ +import type { Sgg } from "@/entities/statistics/model/statistics-interface"; + +/** 조회 시군구가 전체(ALL)면 시도의 전체 옵션, 특정 구면 해당 구만 */ +export function filterSggOptionsBySearchGugun( + sggOptions: readonly Sgg[], + gugun: string | null | undefined, +): Sgg[] { + const selected = gugun?.trim(); + if (!selected || selected === "ALL") { + return [...sggOptions]; + } + return sggOptions.filter((s) => s.gugun === selected); +} diff --git a/apps/st/src/entities/statistics/api/input/statistics-input-sewage-excreta-slurge-service.ts b/apps/st/src/entities/statistics/api/input/statistics-input-sewage-excreta-slurge-service.ts index 57a908a37..a608ca82a 100644 --- a/apps/st/src/entities/statistics/api/input/statistics-input-sewage-excreta-slurge-service.ts +++ b/apps/st/src/entities/statistics/api/input/statistics-input-sewage-excreta-slurge-service.ts @@ -22,6 +22,8 @@ import type { SewageSlurgeProcessingFacStatusSubmitRequest, SewageSlurgeProcessingFacStatusSubmitResponse, SlurgeProcessingFacStatusApiResponse, + SlurgeProcessingFacStatusOperationDataUpdateRequest, + SlurgeProcessingFacStatusOperationDataUpdateResponse, SlurgeProcessingFacStatusSaveRequest, SlurgeProcessingFacStatusSaveResponse, SlurgeProcessingFacStatusSubmitRequest, @@ -68,6 +70,18 @@ export class StatisticsInputSewageExcretaSlurgeApiService implements StatisticsI return response.data; } + /** 찌꺼기(슬러지)처리시설현황 운영 데이터 업데이트 — ST00110001 */ + public async updateSlurgeProcessingFacStatusOperationData( + request: SlurgeProcessingFacStatusOperationDataUpdateRequest, + ): Promise { + const response = + await stClient.put( + `${BASE}/slurge-processing-fac-status/operation-data/update`, + request, + ); + return response.data; + } + /** 소화조 운영현황 조회 — ST00110002 */ public async getDigestorOperatingStatusList( params: SewageExcretaSlurgeRequestParams, diff --git a/apps/st/src/entities/statistics/model/input/statistics-input-sewage-excreta-slurge-interface.ts b/apps/st/src/entities/statistics/model/input/statistics-input-sewage-excreta-slurge-interface.ts index be9763b3d..f5556802d 100644 --- a/apps/st/src/entities/statistics/model/input/statistics-input-sewage-excreta-slurge-interface.ts +++ b/apps/st/src/entities/statistics/model/input/statistics-input-sewage-excreta-slurge-interface.ts @@ -205,6 +205,23 @@ export interface SlurgeProcessingFacStatusSubmitResponse { }; } +/** ST00110001 운영 데이터 업데이트 요청 */ +export interface SlurgeProcessingFacStatusOperationDataUpdateRequest { + statsYr: string; + ctpvNm: string; + /** 도에서만 사용, 특·광역시는 빈 값 */ + sggNm?: string; + sewerBzmnCd: string; + userUuid: string; +} + +/** ST00110001 운영 데이터 업데이트 응답 */ +export interface SlurgeProcessingFacStatusOperationDataUpdateResponse { + status: string; + message?: string; + data?: unknown | null; +} + /** * ST00110002 조회 `data.digestorOperatingStatusList[]` 한 행. * `DigestorOperatingStatusInpColumn` fieldName과 동일 (`ctpvNm` 그리드 값은 `commonInfo.ctpvNm` 시도명). @@ -561,6 +578,10 @@ export interface StatisticsInputSewageExcretaSlurgeService { submitSlurgeProcessingFacStatus( request: SlurgeProcessingFacStatusSubmitRequest, ): Promise; + /** 찌꺼기(슬러지)처리시설현황 운영 데이터 업데이트 — ST00110001 */ + updateSlurgeProcessingFacStatusOperationData( + request: SlurgeProcessingFacStatusOperationDataUpdateRequest, + ): Promise; /** 소화조 운영현황 조회 — ST00110002 */ getDigestorOperatingStatusList( params: SewageExcretaSlurgeRequestParams,