From 792e38c0c5db037f9dfa7945088da6dea40a8eb5 Mon Sep 17 00:00:00 2001 From: swcho Date: Mon, 11 Aug 2025 17:39:59 +0900 Subject: [PATCH 01/12] =?UTF-8?q?feat:=20-=20=EC=9A=B4=EC=98=81=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EA=B2=80=EC=83=89=EC=97=90=20=ED=95=98=EC=88=98?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=EA=B5=AC=EC=97=AD=20=EC=BB=AC=EB=9F=BC=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20-=20=EA=B8=B0=EB=B3=B8=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=20=ED=95=98=EC=88=98=EA=B4=80=EB=A1=9C=20=EA=B2=80=EC=83=89?= =?UTF-8?q?=EC=97=90=20=EC=8B=9C=EB=8F=84,=20=EC=8B=9C=EA=B5=B0=EA=B5=AC,?= =?UTF-8?q?=20=EC=9A=A9=EB=8F=84=20=EC=BB=AC=EB=9F=BC=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=20-=20=EA=B3=B5=ED=86=B5=20=EC=BD=94=EB=93=9C=20=EC=8B=9C?= =?UTF-8?q?=EB=8F=84,=20=EC=8B=9C=EA=B5=B0=EA=B5=AC=20API=20=EC=9B=90?= =?UTF-8?q?=EC=95=A4=EC=98=AC=20->=20=EC=95=8C=EC=95=A0=EC=8A=A4=EC=9B=90?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/sn/app/(map-layout)/layout.tsx | 5 +- .../map/components/common/table.ts | 9 ++-- .../(map-layout)/map/searchModal/basicTab.tsx | 14 ++++-- .../map/searchModal/operationTab.tsx | 15 +++++- .../map/searchModal/searchModal.tsx | 49 +++++++++++++------ .../(map-layout)/map/searchModal/swagePpl.tsx | 26 ++++++++-- .../map/searchModal/swagePrcsFclt.tsx | 10 ++-- .../map/searchModal/swagePrcsZone.tsx | 12 ++--- .../app/(with-base-layout)/ii/BaseLayout.tsx | 12 ++--- apps/sn/app/(with-base-layout)/layout.tsx | 5 +- .../ui/ctpvSggPrcsFcltSelectBox.tsx | 39 ++++++--------- apps/sn/app/store/index.ts | 48 +++++++++--------- apps/sn/app/store/useStore.ts | 16 +++--- .../src/ui/map/searchBar/procSearchBar.tsx | 30 +++++++----- 14 files changed, 174 insertions(+), 116 deletions(-) diff --git a/apps/sn/app/(map-layout)/layout.tsx b/apps/sn/app/(map-layout)/layout.tsx index 2077e5756..2ea6758b3 100644 --- a/apps/sn/app/(map-layout)/layout.tsx +++ b/apps/sn/app/(map-layout)/layout.tsx @@ -19,10 +19,11 @@ export default function MapLayout({ const setCurrentMenuInfo = useMenuStore((state) => state.setCurrentMenuInfo); - const { fetchCtpvSggData, fetchBIZ_SE_CD, fetchBIZ_TY_CD } = useStore(); + const { fetchCtpv, fetchSgg, fetchBIZ_SE_CD, fetchBIZ_TY_CD } = useStore(); useEffect(() => { - fetchCtpvSggData(); + fetchCtpv(); + fetchSgg(); fetchBIZ_SE_CD(); fetchBIZ_TY_CD(); }, []); diff --git a/apps/sn/app/(map-layout)/map/components/common/table.ts b/apps/sn/app/(map-layout)/map/components/common/table.ts index 1e34f5475..238ba7599 100644 --- a/apps/sn/app/(map-layout)/map/components/common/table.ts +++ b/apps/sn/app/(map-layout)/map/components/common/table.ts @@ -31,17 +31,20 @@ export const MsSwagePplCol2 = [ { id: 'rowNumber', title: '일련\n번호' }, { id: 'fcltMngNo', title: '시설\n관리번호' }, { id: 'instMngNo', title: '기관\n관리번호' }, + { id: 'ctpvNm', title: '시도' }, + { id: 'sggNm', title: '시군구' }, { id: 'instlYmd', title: '설치일자' }, // { id: 'mapshtNo', title: '도엽번호' }, + { id: 'usgCd', title: '용도' }, { id: 'pdmtVl', title: '관경\n(mm)' }, { id: 'prlgVl', title: '연장\n(m)' }, - { id: 'avgGrdn', title: '평균구배\n(m/m)' }, + // { id: 'avgGrdn', title: '평균구배\n(m/m)' }, { id: 'tmptDpth', title: '시점깊이\n(m)' }, { id: 'tmptMhlMngNo', title: '시점맨홀\n관리번호' }, { id: 'scendDpth', title: '종점깊이\n(m)' }, { id: 'scendMhlMngNo', title: '종점맨홀\n관리번호' }, - { id: 'vrtcLen', title: '세로길이\n(m)' }, - { id: 'wdthLen', title: '가로길이\n(m)' }, + // { id: 'vrtcLen', title: '세로길이\n(m)' }, + // { id: 'wdthLen', title: '가로길이\n(m)' }, // { id: 'fcltyShpCd', title: '시설물형태코드' }, // { id: 'fid', title: 'FID' }, // { id: 'ftreSmbolCd', title: '지형지물부호코드' }, diff --git a/apps/sn/app/(map-layout)/map/searchModal/basicTab.tsx b/apps/sn/app/(map-layout)/map/searchModal/basicTab.tsx index 018f67883..7a783f139 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/basicTab.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/basicTab.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { YearRangeSelectBox } from '@/components/ui/YearRangeSelectBox'; import { SelectBox } from '@common/business_components/ui'; -import { Button, Input, Label } from '@common/components'; +import { Button, Label } from '@common/components'; import SwagePpl from './swagePpl'; import SwagePrcsFclt from './swagePrcsFclt'; import SwagePrcsZone from './swagePrcsZone'; @@ -20,8 +20,8 @@ export const BASIC_TYPES = [ interface BasicTabProps { basicType: string; - city: number; - sgg: number; + city: string; + sgg: string; start1: string; start2: string; end1: string; @@ -31,9 +31,9 @@ interface BasicTabProps { yearFilter: { start: string; end: string; }; handleSearch: () => void; setBasicType: (type: string) => void; - setCity: (city: number) => void; + setCity: (city: string) => void; setCtpvName: (name: string) => void; - setSgg: (sgg: number) => void; + setSgg: (sgg: string) => void; setSggName: (name: string) => void; setYearFilter: (filter: { start: string; end: string }) => void; setStart1: (value: string) => void; @@ -97,6 +97,8 @@ const BasicTab: React.FC = ({ start2={start2} end1={end1} end2={end2} + city={city} + sgg={sgg} yearFilter={yearFilter} setVar1={setVar1} setVar2={setVar2} @@ -104,6 +106,8 @@ const BasicTab: React.FC = ({ setStart2={setStart2} setEnd1={setEnd1} setEnd2={setEnd2} + setCity={setCity} + setSgg={setSgg} setYearFilter={setYearFilter} handleSearch={handleSearch} /> diff --git a/apps/sn/app/(map-layout)/map/searchModal/operationTab.tsx b/apps/sn/app/(map-layout)/map/searchModal/operationTab.tsx index 155a17215..446632965 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/operationTab.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/operationTab.tsx @@ -24,7 +24,10 @@ export const operationTableHeadlist = [ export const operationMaintenanceTableHeadlist = [ { id: 'rowNumber', title: '일련번호' }, { id: "fcltMngNo", title: "관리번호" }, + { id: "swtrmt_zone_nm", title: "처리구역" }, { id: "usgCd", title: "용도" }, + // { id: "lgalDrblyr", title: "내용연수" }, + // { id: "acqsPrmpc", title: "취득금액" }, { id: "mqltCd", title: "재질" }, { id: "pdmtVl", title: "관경(mm)" }, { id: "prlgVl", title: "연장(m)" }, @@ -35,7 +38,10 @@ export const operationMaintenanceTableHeadlist = [ export const operationCleaningTableHeadlist = [ { id: 'rowNumber', title: '일련번호' }, { id: "fcltMngNo", title: "관리번호" }, + { id: "swtrmt_zone_nm", title: "처리구역" }, { id: "usgCd", title: "용도" }, + // { id: "lgalDrblyr", title: "내용연수" }, + // { id: "acqsPrmpc", title: "취득금액" }, { id: "mqltCd", title: "재질" }, { id: "pdmtVl", title: "관경(mm)" }, { id: "prlgVl", title: "연장(m)" }, @@ -45,13 +51,18 @@ export const operationCleaningTableHeadlist = [ export const operationInspectionTableHeadlist = [ { id: 'rowNumber', title: '일련번호' }, { id: "fcltMngNo", title: "관리번호" }, + { id: "swtrmt_zone_nm", title: "처리구역" }, { id: "usgCd", title: "용도" }, + // { id: "riskEval", title: "위험평가" }, + // { id: "acqsPrmpc", title: "취득금액" }, + // { id: "lgalDrblyr", title: "내용연수" }, + // { id: "remLife", title: "잔존수명" }, { id: "mqltCd", title: "재질" }, { id: "pdmtVl", title: "관경(mm)" }, { id: "prlgVl", title: "연장(m)" }, { id: "instlYmd", title: "설치일자" }, - { id: "strct_stat_grd", title: "구조적 상태등급" }, - { id: "oper_stat_grd", title: "운영적 상태등급" }, + { id: "strc_stts_grd", title: "구조적 상태등급" }, + { id: "oper_stts_grd", title: "운영적 상태등급" }, ]; interface OperationTabProps { diff --git a/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx b/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx index 71e7c8855..ccce61561 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx @@ -61,9 +61,9 @@ const SearchModal: React.FC = ({ const [isResetSelection, setIsResetSelection] = useState(false); const [isResetDetailSelection, setIsResetDetailSelection] = useState(false); const [detailBizId, setDetailBizId] = useState(0); - const [city, setCity] = useState(0); + const [ctpvCd, setCtpvCd] = useState("0"); const [ctpvName, setCtpvName] = useState(''); - const [sgg, setSgg] = useState(0); + const [sggCd, setSggCd] = useState("0"); const [sggName, setSggName] = useState(''); const [start1, setStart1] = useState(""); const [start2, setStart2] = useState(""); @@ -76,7 +76,7 @@ const SearchModal: React.FC = ({ // 시작, 종료 const [yearFilter, setYearFilter] = useState({ start: "", end: "" }); - const { BIZ_TY_CD } = useStore(); + const { ctpv, sgg, BIZ_TY_CD, BIZ_SE_CD } = useStore(); // 오늘 날짜 구하기 @@ -104,8 +104,8 @@ const SearchModal: React.FC = ({ const dynamicHeadlist2: { id: string, title: string }[] = useMemo(() => { if (activeTab === 'operation') { if (workType === WORK_TYPES[0]?.val) return operationMaintenanceTableHeadlist; - if (workType === WORK_TYPES[1]?.val) return operationCleaningTableHeadlist; - if (workType === WORK_TYPES[2]?.val) return operationInspectionTableHeadlist; + if (workType === WORK_TYPES[1]?.val) return operationInspectionTableHeadlist; + if (workType === WORK_TYPES[2]?.val) return operationCleaningTableHeadlist; } return []; @@ -121,8 +121,8 @@ const SearchModal: React.FC = ({ setVar2(""); setVar3(""); setVar4(""); - setCity(0); - setSgg(0); + setCtpvCd("0"); + setSggCd("0"); setYearFilter({ start: "", end: "", @@ -204,14 +204,30 @@ const SearchModal: React.FC = ({ const dataWithRowNumber = (res.data.data || []).map((item: any, index: number) => { // 🎯 먼저 각 아이템을 포맷팅 const formattedItem = formatDisplayData(item); - const matched = MS_SWAGE_MHL_CODES.find(code => code.val === item?.mqltCd?.trim()); + + let ctpvCd = item?.ctpvNm ?? formattedItem?.ctpvNm ?? ''; + let sggCd = item?.sggNm ?? formattedItem?.sggNm ?? ''; + + if (!ctpvCd || !sggCd) { + const code = String(item?.pbadmsEmdCd ?? formattedItem?.pbadmsEmdCd ?? '').trim(); + if (!ctpvCd && code) ctpvCd = code.slice(0, 2); + if (!sggCd && code) sggCd = code.slice(0, 5); + } + + const matchedMhlCode = MS_SWAGE_MHL_CODES.find(code => code.val === item?.mqltCd?.trim()); + const ctpvNm = ctpv.find(code => code.val.trim() === ctpvCd)?.text || ctpvCd; + const sggNm = sgg.find(code => code.val.trim() === sggCd)?.text || '-'; + const usgCdObj = MS_SWAGE_PPL_USE_CODES.find(code => code.val === item?.usgCd?.trim()); // 추가 처리 및 일련번호 추가 return { ...formattedItem, rowNumber: (curPage - 1) * 10 + index + 1, // 1부터 시작하는 일련번호 추가 scsYn: item.scsYn === null || item.scsYn === undefined ? 'N' : item.scsYn, // scsYn이 null이면 'N'으로 변경 - mqltCd: matched ? matched.text : item.mqltCd, + mqltCd: matchedMhlCode ? matchedMhlCode.text : item.mqltCd, + usgCd: usgCdObj ? usgCdObj.text : item.usgCd, + ctpvNm, + sggNm, }; }); @@ -286,7 +302,8 @@ const SearchModal: React.FC = ({ // 추후 작성 예정 if (var1) cqlFilters.push(`usg_cd='${var1}'`); if (var2) cqlFilters.push(`mqlt_cd='${var2}'`); - if (var3) cqlFilters.push(`pbadms_emd_cd='${var3}'`); + if (ctpvCd !== '0') cqlFilters.push(`pbadms_emd_cd LIKE '${ctpvCd.trim()}%'`); + if (ctpvCd !== '0' && sggCd !== '0') cqlFilters.push(`pbadms_emd_cd LIKE '${sggCd}%'`); // 설치년도 범위 const startDate = getDateString( yearFilter.start, @@ -354,8 +371,8 @@ const SearchModal: React.FC = ({ // 하수처리구역용 CQL 필터 생성 const zoneCqlFilters = () => { const cqlFilters: string[] = []; - if (city) cqlFilters.push(`ctpv_cd='${city}'`); - if (sgg) cqlFilters.push(`sgg_cd='${sgg}'`); + if (ctpvCd !== '' && ctpvCd !== '0') cqlFilters.push(`ctpv_cd='${ctpvCd.trim()}'`); + if (sggCd !== '' && sggCd !== '0') cqlFilters.push(`sgg_cd='${sggCd.trim()}'`); if (var1) cqlFilters.push(`swtrmt_zone_nm ILIKE '%${var1}%'`); if (var2) cqlFilters.push(`swtrmt_fclt_nm ILIKE '%${var2}%'`); return cqlFilters; @@ -563,8 +580,8 @@ const SearchModal: React.FC = ({ {activeTab === 'basic' && ( = ({ yearFilter={yearFilter} handleSearch={handleSearch} setBasicType={setBasicType} - setCity={setCity} + setCity={setCtpvCd} setCtpvName={setCtpvName} - setSgg={setSgg} + setSgg={setSggCd} setSggName={setSggName} setYearFilter={setYearFilter} setStart1={setStart1} diff --git a/apps/sn/app/(map-layout)/map/searchModal/swagePpl.tsx b/apps/sn/app/(map-layout)/map/searchModal/swagePpl.tsx index f729ab6eb..1676b469a 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/swagePpl.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/swagePpl.tsx @@ -5,6 +5,7 @@ import { SelectBox } from '@common/business_components/ui'; import { Button, Input, Label } from '@common/components'; import React from 'react'; import { MS_SWAGE_PPL_CODES, MS_SWAGE_PPL_USE_CODES } from '../components/common/table'; +import { CtpvSggPrcsFcltSelectBox } from '@/components/ui/ctpvSggPrcsFcltSelectBox'; interface SwagePplProps { var1: string; @@ -13,6 +14,8 @@ interface SwagePplProps { start2: string; end1: string; end2: string; + city: string; + sgg: string; yearFilter: { start: string; end: string }; setVar1: (value: string) => void; setVar2: (value: string) => void; @@ -20,6 +23,8 @@ interface SwagePplProps { setStart2: (value: string) => void; setEnd1: (value: string) => void; setEnd2: (value: string) => void; + setCity: (value: string) => void; + setSgg: (value: string) => void; setYearFilter: (filter: { start: string; end: string }) => void; handleSearch: () => void; } @@ -31,6 +36,8 @@ const SwagePpl: React.FC = ({ start2, end1, end2, + city, + sgg, yearFilter, setVar1, setVar2, @@ -38,6 +45,8 @@ const SwagePpl: React.FC = ({ setStart2, setEnd1, setEnd2, + setCity, + setSgg, setYearFilter, handleSearch, }) => { @@ -45,6 +54,15 @@ const SwagePpl: React.FC = ({ return (
+ { + setCity(sidoId); + setSgg("0"); + }} + onSigunguChange={setSgg} + /> {/* 설치년도 */} = ({ selectContentClass="z-[101]" /> {/* 재질 */} - + {/* = ({ setVar2(String(val)); }} selectContentClass="z-[101]" - /> + /> */} {/* 관경 */} = ({ }} /> {/* 연장 */} - + {/* = ({ handleSearch(); } }} - /> + /> */} {/* 조회 버튼 */}
diff --git a/apps/sn/app/(map-layout)/map/searchModal/swagePrcsFclt.tsx b/apps/sn/app/(map-layout)/map/searchModal/swagePrcsFclt.tsx index 8779f0fa5..a3db595a5 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/swagePrcsFclt.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/swagePrcsFclt.tsx @@ -12,17 +12,17 @@ interface SwagePrcsFcltProps { start2: string; end1: string; end2: string; - city: number; - sgg: number; + city: string; + sgg: string; yearFilter: { start: string; end: string }; setVar1: (value: string) => void; setStart1: (value: string) => void; setStart2: (value: string) => void; setEnd1: (value: string) => void; setEnd2: (value: string) => void; - setCity: (value: number) => void; + setCity: (value: string) => void; setCtpvName: (name: string) => void; - setSgg: (value: number) => void; + setSgg: (value: string) => void; setSggName: (name: string) => void; setYearFilter: (filter: { start: string; end: string }) => void; handleSearch: () => void; @@ -52,7 +52,7 @@ const SwagePrcsFclt: React.FC = ({ sigungu={sgg} onSidoChange={(sidoId) => { setCity(sidoId); - setSgg(0); + setSgg("0"); }} onSigunguChange={setSgg} setCtpvName={setCtpvName} diff --git a/apps/sn/app/(map-layout)/map/searchModal/swagePrcsZone.tsx b/apps/sn/app/(map-layout)/map/searchModal/swagePrcsZone.tsx index 8cb304d2a..9f8e8a181 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/swagePrcsZone.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/swagePrcsZone.tsx @@ -7,12 +7,12 @@ import React from 'react'; interface swagePrcsZoneProps { var1: string; var2: string; - city: number; - sgg: number; + city: string; + sgg: string; setVar1: (value: string) => void; setVar2: (value: string) => void; - setCity: (value: number) => void; - setSgg: (value: number) => void; + setCity: (value: string) => void; + setSgg: (value: string) => void; handleSearch: () => void; } @@ -34,9 +34,9 @@ const swagePrcsZone: React.FC = ({ { + onSidoChange={(sidoId: string) => { setCity(sidoId); - setSgg(0); + setSgg("0"); }} onSigunguChange={setSgg} /> diff --git a/apps/sn/app/(with-base-layout)/ii/BaseLayout.tsx b/apps/sn/app/(with-base-layout)/ii/BaseLayout.tsx index 275126474..68f5ec068 100644 --- a/apps/sn/app/(with-base-layout)/ii/BaseLayout.tsx +++ b/apps/sn/app/(with-base-layout)/ii/BaseLayout.tsx @@ -39,8 +39,8 @@ type BaseLayout = { firstDivBtn?: boolean selectBox?: SelectBox showDatePicker?: boolean; - ctpvCd: number; - sggCd: number; + ctpvCd: string; + sggCd: string; sggName?: string; sigungu?: ApiSelectOption selectedSwagePrcsFclt?: string | number; @@ -49,8 +49,8 @@ type BaseLayout = { setAplcnYmFrom?: (aplcnYmFrom: string) => void; aplcnYmTo?: string setAplcnYmTo?: (aplcnYmTo: string) => void; - setCtpvCd: (ctpv: number) => void; - setSggCd: (sgg: number) => void; + setCtpvCd: (ctpv: string) => void; + setSggCd: (sgg: string) => void; setSggName?: (sggName: string) => void; setSwtrmtFcltNm?: (swtrmtFcltNm: string) => void; setIsLoading?: (isLoading: boolean) => void; @@ -178,9 +178,9 @@ const BaseLayout = ({ sido={ctpvCd} sigungu={sggCd} sggName={sggName} - onSidoChange={(sidoId: number) => { + onSidoChange={(sidoId: string) => { setCtpvCd(sidoId); - setSggCd(0); + setSggCd('0'); }} onSigunguChange={setSggCd} setSggName={setSggName} diff --git a/apps/sn/app/(with-base-layout)/layout.tsx b/apps/sn/app/(with-base-layout)/layout.tsx index f8e046717..229415e53 100644 --- a/apps/sn/app/(with-base-layout)/layout.tsx +++ b/apps/sn/app/(with-base-layout)/layout.tsx @@ -20,10 +20,11 @@ export default function WithBaseLayout({ const setCurrentMenuInfo = useMenuStore((state) => state.setCurrentMenuInfo); - const { fetchCtpvSggData, fetchBIZ_SE_CD, fetchBIZ_TY_CD } = useStore(); + const { fetchCtpv, fetchSgg, fetchBIZ_SE_CD, fetchBIZ_TY_CD } = useStore(); useEffect(() => { - fetchCtpvSggData(); + fetchCtpv(); + fetchSgg(); fetchBIZ_SE_CD(); fetchBIZ_TY_CD(); }, []); diff --git a/apps/sn/app/components/ui/ctpvSggPrcsFcltSelectBox.tsx b/apps/sn/app/components/ui/ctpvSggPrcsFcltSelectBox.tsx index a7472d4c0..9b9df0724 100644 --- a/apps/sn/app/components/ui/ctpvSggPrcsFcltSelectBox.tsx +++ b/apps/sn/app/components/ui/ctpvSggPrcsFcltSelectBox.tsx @@ -1,4 +1,4 @@ -import React, { useState, useMemo, useEffect } from "react"; +import React, { useState, useEffect } from "react"; import { SelectBox } from '@common/business_components/ui' import { Label } from '@common/components'; import useStore from '../../store/useStore'; @@ -10,11 +10,11 @@ interface ApiSelectOption { val: string; } interface CtpvSggPrcsFcltSelectBoxProps { - sido: number; - sigungu: number; + sido: string; + sigungu: string; sggName?: string; - onSidoChange: (id: number) => void; - onSigunguChange: (id: number) => void; + onSidoChange: (id: string) => void; + onSigunguChange: (id: string) => void; setCtpvName?: (name: string) => void; setSggName?: (name: string) => void; className?: string; @@ -46,14 +46,17 @@ export function CtpvSggPrcsFcltSelectBox({ useEffect(() => { (async () => { - onSidoChange(0); - onSigunguChange(0); + onSidoChange("0"); + onSigunguChange("0"); if (setCtpvName && setSggName) { setCtpvName(""); setSggName(""); } if (setSwtrmtFcltNm) setSwtrmtFcltNm(""); })(); + + console.log("ctpv", ctpv); + console.log("sgg", sgg); }, []); useEffect(() => { @@ -112,15 +115,11 @@ export function CtpvSggPrcsFcltSelectBox({ className="w-60 mr-8" selectClass="rounded-lg bg-white" label="" - selectArray={ - [defaultOption, - ...ctpv.map(opt => ({ val: opt.id, text: opt.name })) - ] - } + selectArray={[defaultOption, ...ctpv]} value={sido} onSelectValue={val => { - onSidoChange(Number(val)); - if (setCtpvName) setCtpvName(ctpv.find(opt => Number(opt.id) === Number(val))?.name || ""); + onSidoChange(String(val)); + if (setCtpvName) setCtpvName(ctpv.find(opt => String(opt.val) === String(val))?.text || ""); if (setSwtrmtFcltNm) setSwtrmtFcltNm(""); }} selectContentClass="z-[101]" @@ -130,17 +129,11 @@ export function CtpvSggPrcsFcltSelectBox({ className="w-48" selectClass="w-48 rounded-lg bg-white truncate" label="" - selectArray={ - [defaultOption, - ...sgg - .filter(opt => String(opt.id).slice(0, 2) === String(sido)) - .map(opt => ({ val: opt.id, text: opt.name })) - ] - } + selectArray={[defaultOption, ...sgg.filter(opt => opt.val.startsWith(sido.slice(0, 2)))]} value={sigungu} onSelectValue={val => { - onSigunguChange(Number(val)) - if (setSggName) setSggName(sgg.find(opt => Number(opt.id) === Number(val))?.name || ""); + onSigunguChange(String(val)) + if (setSggName) setSggName(sgg.find(opt => String(opt.val) === String(val))?.text || ""); if (setSwtrmtFcltNm) setSwtrmtFcltNm("") }} selectContentClass="z-[101]" diff --git a/apps/sn/app/store/index.ts b/apps/sn/app/store/index.ts index 40e094480..de827c9a1 100644 --- a/apps/sn/app/store/index.ts +++ b/apps/sn/app/store/index.ts @@ -1,8 +1,6 @@ import { getCmsData } from "@/components/lib/api"; -export interface Option { id: number, name: string } - export type BIZ_CD_TYPE = { lwpoCd: string, upCd: string, @@ -11,28 +9,34 @@ export type BIZ_CD_TYPE = { prntLwpoCd: null }; -export const fetchCtpvSggData = async (set: (state: any) => void) => { - try { - const ctpvData = await getCmsData('/api/v1/code/cache/ADSTDSTRCD/Y'); - const ctpvList: Option[] = ctpvData - .filter((item: any) => typeof item.lwpoCd === 'string' && item.lwpoCd.length === 2) - .map((feature: any) => ({ - id: feature.lwpoCd, - name: feature.lwpoCdNm - })); +export const fetchCtpv = async (set: (state: any) => void) => { + const url = `/geoserver/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=hasudo:tb_ms_ctpv&outputFormat=application/json&propertyName=mctpv_korn_nm,mctpv_cd`; + const res = await fetch(url).then(res => res.json()); - const sggList: Option[] = ctpvData - .filter((item: any) => typeof item.lwpoCd === 'string' && item.lwpoCd.length !== 2) - .map((item: any) => ({ - id: item.lwpoCd, - name: item.lwpoCdNm - })); + const list = res.features + .map((f: any) => ({ + text: f.properties.mctpv_korn_nm, + val: f.properties.mctpv_cd, + })) + .sort((a, b) => a.text.localeCompare(b.text, 'ko')); - set({ ctpv: ctpvList, sgg: sggList }); - } catch (e: any) { - // alert("시도, 시군구 데이터 로드 실패: " + e.message); - console.error("CTPV 데이터 로드 실패:", e); - } + console.log('시도 데이터', list); + set({ ctpv: list}); +}; + +export const fetchSgg = async (set: (state: any) => void) => { + const url = `/geoserver/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=hasudo:tb_ms_sgg&outputFormat=application/json&propertyName=sgg_cd,sgg_korn_nm`; + const res = await fetch(url).then(res => res.json()); + + const list = res.features + .map((f: any) => ({ + text: f.properties.sgg_korn_nm, + val: f.properties.sgg_cd, + })) + .sort((a, b) => a.text.localeCompare(b.text, 'ko')); + + console.log('시군구 데이터', list); + set({ sgg: list }); }; export const fetchBIZ_SE_CD = async (set: (state: any) => void) => { diff --git a/apps/sn/app/store/useStore.ts b/apps/sn/app/store/useStore.ts index b2ae014fa..678090ed7 100644 --- a/apps/sn/app/store/useStore.ts +++ b/apps/sn/app/store/useStore.ts @@ -1,8 +1,6 @@ import { create } from "zustand"; -import { getGeoData, getCmsData } from "@/components/lib/api"; -import { fetchCtpvSggData, fetchBIZ_SE_CD, fetchBIZ_TY_CD } from "./index"; - -interface Option { id: number, name: string } +import { fetchCtpv, fetchSgg, fetchBIZ_SE_CD, fetchBIZ_TY_CD } from "./index"; +import { type SelectDataType } from "@common/business_components"; export type BIZ_CD_TYPE = { lwpoCd: string, @@ -13,11 +11,12 @@ export type BIZ_CD_TYPE = { }; interface SnStoreState { - ctpv: Option[]; - sgg: Option[]; + ctpv: SelectDataType[]; + sgg: SelectDataType[]; BIZ_SE_CD: BIZ_CD_TYPE[]; BIZ_TY_CD: BIZ_CD_TYPE[]; - fetchCtpvSggData: () => Promise; + fetchCtpv: () => Promise; + fetchSgg: () => Promise; fetchBIZ_SE_CD: () => Promise; fetchBIZ_TY_CD: () => Promise; } @@ -27,7 +26,8 @@ const useStore = create((set) => ({ sgg: [], BIZ_SE_CD: [], BIZ_TY_CD: [], - fetchCtpvSggData: () => fetchCtpvSggData(set), + fetchCtpv: () => fetchCtpv(set), + fetchSgg: () => fetchSgg(set), fetchBIZ_SE_CD: () => fetchBIZ_SE_CD(set), fetchBIZ_TY_CD: () => fetchBIZ_TY_CD(set), })); diff --git a/packages/common/business_components/src/ui/map/searchBar/procSearchBar.tsx b/packages/common/business_components/src/ui/map/searchBar/procSearchBar.tsx index 21239bd7b..2f0eb2be9 100644 --- a/packages/common/business_components/src/ui/map/searchBar/procSearchBar.tsx +++ b/packages/common/business_components/src/ui/map/searchBar/procSearchBar.tsx @@ -43,10 +43,12 @@ export const ProcSearchBar = ({ gisMaps, facilityTypes }: SearchBarProps) => { const url = `/geoserver/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=hasudo:tb_ms_ctpv&outputFormat=application/json&propertyName=mctpv_korn_nm,mctpv_cd`; const res = await fetch(url).then(res => res.json()); - const list = res.features.map((f: any) => ({ - text: f.properties.mctpv_korn_nm, - val: f.properties.mctpv_cd, - })); + const list = res.features + .map((f: any) => ({ + text: f.properties.mctpv_korn_nm, + val: f.properties.mctpv_cd, + })) + .sort((a, b) => a.text.localeCompare(b.text, 'ko')); setSidoData([{ text: "시도", val: "0" }, ...list]); }; @@ -54,10 +56,12 @@ export const ProcSearchBar = ({ gisMaps, facilityTypes }: SearchBarProps) => { const url = `/geoserver/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=hasudo:tb_ms_sgg&outputFormat=application/json&propertyName=sgg_cd,sgg_korn_nm`; const res = await fetch(url).then(res => res.json()); - const list = res.features.map((f: any) => ({ - text: f.properties.sgg_korn_nm, - val: f.properties.sgg_cd, - })); + const list = res.features + .map((f: any) => ({ + text: f.properties.sgg_korn_nm, + val: f.properties.sgg_cd, + })) + .sort((a, b) => a.text.localeCompare(b.text, 'ko')); setSigunData(list); }; @@ -90,10 +94,12 @@ export const ProcSearchBar = ({ gisMaps, facilityTypes }: SearchBarProps) => { url = `${url}&typeName=hasudo:${type}&cql_filter=${cqlFilter}`; const res = await fetch(url); const json = await res.json(); - list = json.features.map((f: any) => ({ - text: f.properties.swtrmt_fclt_nm ?? "(이름없음)", - val: f.id, - })); + list = json.features + .map((f: any) => ({ + text: f.properties.swtrmt_fclt_nm ?? "(이름없음)", + val: f.id, + })) + .sort((a, b) => a.text.localeCompare(b.text, 'ko')); } else if ( type === "tb_wr_bdst_ruse_fclt" // 재이용시설 ) { From 4c76e572b270eddf04aeaaef0b1713236ff01bf9 Mon Sep 17 00:00:00 2001 From: swcho Date: Mon, 11 Aug 2025 17:49:10 +0900 Subject: [PATCH 02/12] =?UTF-8?q?fix:=20reportTab=20=EC=8B=9C=EB=8F=84,=20?= =?UTF-8?q?=EC=8B=9C=EA=B5=B0=EA=B5=AC=20=ED=83=80=EC=9E=85=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../map/searchModal/reportTab.tsx | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/apps/sn/app/(map-layout)/map/searchModal/reportTab.tsx b/apps/sn/app/(map-layout)/map/searchModal/reportTab.tsx index fa4f35afd..20d9768a2 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/reportTab.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/reportTab.tsx @@ -4,7 +4,7 @@ import { Button, Label } from '@common/components'; import { YearRangeSelectBox } from '@/components/ui/YearRangeSelectBox'; import { SelectBox, UiTable } from '@common/business_components/ui'; import LoadingOverlay from '@/components/ui/LoadingBar'; -import { addFileName, flattenFolders, getFileDownload, getDcTree, useDcTree, reportGubuns } from './searchModalReportApi'; +import { addFileName, flattenFolders, getFileDownload, useDcTree, reportGubuns } from './searchModalReportApi'; import useStore from '../../../store/useStore'; import { CtpvSggPrcsFcltSelectBox } from '@/components/ui/ctpvSggPrcsFcltSelectBox'; @@ -37,8 +37,8 @@ const ReportTab: React.FC = ({ open, isSearch = true, ctpvNm, sg const [tableCount, setTableCount] = useState(0); const [curPage, setCurPage] = useState(1); const [yearFilter, setYearFilter] = useState({ start: "", end: "" }); - const [ctpvCd, setCtpvCd] = useState(0); - const [sggCd, setSggCd] = useState(0); + const [ctpvCd, setCtpvCd] = useState('0'); + const [sggCd, setSggCd] = useState('0'); const [reportGubun, setReportGubun] = useState("0"); // const [gubun, setGubun] = useState(""); @@ -49,8 +49,8 @@ const ReportTab: React.FC = ({ open, isSearch = true, ctpvNm, sg useEffect(() => { // filterParams 초기화 - setCtpvCd(0); - setSggCd(0); + setCtpvCd('0'); + setSggCd('0'); setReportGubun('0'); setYearFilter({ start: "", end: "" }); setShowTable(false); @@ -62,8 +62,8 @@ const ReportTab: React.FC = ({ open, isSearch = true, ctpvNm, sg }, [open]); useEffect(() => { - let newCtpvCd = ctpv.find((n) => n.name === ctpvNm)?.id || 0; - let newSggCd = sgg.find((n) => n.name === sggNm)?.id || 0; + const newCtpvCd = ctpv.find((n) => n.text === ctpvNm)?.val || '0'; + const newSggCd = sgg.find((n) => n.text === sggNm)?.val || '0'; setCtpvCd(newCtpvCd); setSggCd(newSggCd); @@ -84,9 +84,9 @@ const ReportTab: React.FC = ({ open, isSearch = true, ctpvNm, sg if (showTable) fetchFilteredData(); }, [curPage]); - const handleCtpvCdChange = (sidoId: number) => { + const handleCtpvCdChange = (sidoId: string) => { setCtpvCd(sidoId); - setSggCd(0); + setSggCd('0'); } // 조회 버튼 클릭 시 1페이지로 이동 및 데이터 초기화 @@ -122,17 +122,18 @@ const ReportTab: React.FC = ({ open, isSearch = true, ctpvNm, sg console.log("필터링 전 보고서 데이터:", filterReportData); console.log('ctpv, sgg, ctpvCd, sggCd', ctpv, sgg, ctpvCd, sggCd); - if (ctpvCd) { // 시도검색 + if (ctpvCd !== '0') { // 시도검색 console.log('시도 실행되나'); - const sidoOption = ctpv.find((n) => String(n.id) === String(ctpvCd)); + console.log('ctpvCd.trim()', ctpvCd.trim()); + const sidoOption = ctpv.find((n) => n.val.trim() === ctpvCd.trim()); console.log('sidoOption', sidoOption) - filterReportData = filterReportData.filter(item => item.sido === sidoOption?.name); + filterReportData = filterReportData.filter(item => item.sido === sidoOption?.text); console.log('시도 필터링 후:', filterReportData); } - if (sggCd) { // 시군구검색 + if (sggCd !== '0') { // 시군구검색 console.log('시군구 실행되나'); - const sigunguOption = sgg.find((n) => String(n.id) === String(sggCd)); - filterReportData = filterReportData.filter(item => item.sigungu === sigunguOption?.name); + const sigunguOption = sgg.find((n) => String(n.val) === String(sggCd)); + filterReportData = filterReportData.filter(item => item.sigungu === sigunguOption?.text); console.log('시군구 필터링 후:', filterReportData); } if (reportGubun !== "0") { // 보고서구분검색 @@ -186,7 +187,7 @@ const ReportTab: React.FC = ({ open, isSearch = true, ctpvNm, sg { handleCtpvCdChange(sidoId) }} + onSidoChange={(sidoId: string) => { handleCtpvCdChange(sidoId) }} onSigunguChange={setSggCd} setIsLoading={setIsLoading} /> From 1886bd74e000fb76d97ec0d2f3762b2dc8b829e3 Mon Sep 17 00:00:00 2001 From: swcho Date: Mon, 11 Aug 2025 18:16:37 +0900 Subject: [PATCH 03/12] =?UTF-8?q?fix:=20=EC=8B=9C=EB=8F=84,=20=EC=8B=9C?= =?UTF-8?q?=EA=B5=B0=EA=B5=AC=20=EC=9B=90=EC=95=A4=EC=98=AC=20->=20?= =?UTF-8?q?=EC=95=8C=EC=95=A0=EC=8A=A4=EC=9B=90=20=EB=B3=80=EA=B2=BD?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=9D=B8=ED=95=9C=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../(with-base-layout)/ii/irsetting/page.tsx | 13 ++++------- .../app/(with-base-layout)/ii/rdii/page.tsx | 22 ++++--------------- .../(with-base-layout)/ii/rdiiResult/page.tsx | 16 +++++++------- .../app/(with-base-layout)/ii/result/page.tsx | 16 +++++++------- .../ui/ctpvSggPrcsFcltSelectBox.tsx | 4 +++- 5 files changed, 27 insertions(+), 44 deletions(-) diff --git a/apps/sn/app/(with-base-layout)/ii/irsetting/page.tsx b/apps/sn/app/(with-base-layout)/ii/irsetting/page.tsx index 0f3d710c7..90e9bd440 100644 --- a/apps/sn/app/(with-base-layout)/ii/irsetting/page.tsx +++ b/apps/sn/app/(with-base-layout)/ii/irsetting/page.tsx @@ -42,19 +42,14 @@ interface UploadedFileInfo { // 초기 파일 정보 상태 const initialFileInfo: UploadedFileInfo = { file: null, atflCd: null, atflId: null }; -interface ApiSelectOption { - text: string; - val: string; -} - const IrSetting = () => { const [input1, setInput1] = useState('0.8'); // 오수전환율 초기값 const [input2, setInput2] = useState(''); const [select1, setSelect1] = useState('0'); // 하수처리장코드 const [formResetKey, setFormResetKey] = useState(0); // FileUploadForm 리셋을 위한 key 상태 const [isLoadingResult, setIsLoadingResult] = useState(false); // 로딩 상태 - const [ctpvCd, setCtpvCd] = useState(0); // 시도 코드 상태 - const [sggCd, setSggCd] = useState(0); // 시군구 코드 상태 + const [ctpvCd, setCtpvCd] = useState('0'); // 시도 코드 상태 + const [sggCd, setSggCd] = useState('0'); // 시군구 코드 상태 const [sggName, setSggName] = useState(''); // 시군구 이름 상태 const [swtrmtFcltNm, setSwtrmtFcltNm] = useState(''); // 하수처리시설명 상태 @@ -298,8 +293,8 @@ const IrSetting = () => { // 새로운 JSON 데이터 생성 const combinedAnalysisData = { - ctpvCd: (ctpvCd ? String(ctpvCd) : null), - sggCd: (sggCd ? String(sggCd) : null), // 시군구코드 (선택값) + ctpvCd: ctpvCd !== '0' ? String(ctpvCd).trim() : null, + sggCd: sggCd !== '0' ? String(sggCd) : null, // 시군구코드 (선택값) swtrmtFcltNm: swtrmtFcltNm ?? null, aplcnYm: selectedDate, // 적용연월 drtwSwtcRt: parseFloat(input1) || null, // 오수전환율 (숫자로 변환) diff --git a/apps/sn/app/(with-base-layout)/ii/rdii/page.tsx b/apps/sn/app/(with-base-layout)/ii/rdii/page.tsx index f0da9ad47..aea5c873a 100644 --- a/apps/sn/app/(with-base-layout)/ii/rdii/page.tsx +++ b/apps/sn/app/(with-base-layout)/ii/rdii/page.tsx @@ -95,11 +95,6 @@ interface UploadedFileInfo { // 초기 파일 정보 상태 const initialFileInfo: UploadedFileInfo = { file: null, atflCd: null, atflId: null }; -interface ApiSelectOption { - text: string; - val: string; -} - export default function RTKForm() { const [formResetKey, setFormResetKey] = useState(0); // FileUploadForm 리셋을 위한 key 상태 const [isLoadingResult, setIsLoadingResult] = useState(false); // 로딩 상태 @@ -113,8 +108,8 @@ export default function RTKForm() { ]); const [select1, setSelect1] = useState('0'); // 하수처리장 (swtrmtFcltCd) - const [ctpvCd, setCtpvCd] = useState(0); // 시도 코드 상태 - const [sggCd, setSggCd] = useState(0); // 시군구 코드 상태 + const [ctpvCd, setCtpvCd] = useState('0'); // 시도 코드 상태 + const [sggCd, setSggCd] = useState('0'); // 시군구 코드 상태 const [sggName, setSggName] = useState(''); // 시군구 이름 상태 const [swtrmtFcltNm, setSwtrmtFcltNm] = useState(''); // 하수처리시설명 상태 @@ -290,8 +285,8 @@ export default function RTKForm() { // 새로운 JSON 데이터 생성 const combinedAnalysisData = { aplcnYm: formData.date, // 적용연월 (YYYYMM 형식) - ctpvCd: ctpvCd ? String(ctpvCd) : null, // 시도코드 (선택값) - sggCd: sggCd ? String(sggCd) : null, // 시군구코드 (선택값) + ctpvCd: ctpvCd !== '0' ? String(ctpvCd).trim() : null, // 시도코드 (선택값) + sggCd: sggCd !== '0' ? String(sggCd) : null, // 시군구코드 (선택값) swtrmtFcltNm: swtrmtFcltNm ?? null, atflCd: file1?.atflCd, // 첨부파일CD (오수관망도) atflId: file1?.atflId, // 첨부파일ID (오수관망도) @@ -357,10 +352,6 @@ export default function RTKForm() { name: "initialDepths" }) - const onSubmit = (data: z.infer) => { - console.log("✅ 제출 데이터:", data) - } - // 단위도 계수 테이블 설정 (EditableTableHeadItem 타입 사용 및 id 수정) const unitFactorHeadlist: EditableTableHeadItem[] = [ { id: 'response', title: 'Response', editable: false, width: '150px' }, // width 속성 추가 @@ -377,11 +368,6 @@ export default function RTKForm() { { id: 'Do', title: 'Do', editable: true, inputProps: { type: 'text' } } ]; - // 테이블 페이지 변경 핸들러 - const handlePageChange = (page: number) => { - console.log('Page changed:', page) - } - return ( <> diff --git a/apps/sn/app/(with-base-layout)/ii/rdiiResult/page.tsx b/apps/sn/app/(with-base-layout)/ii/rdiiResult/page.tsx index 784aeb6a5..257916d76 100644 --- a/apps/sn/app/(with-base-layout)/ii/rdiiResult/page.tsx +++ b/apps/sn/app/(with-base-layout)/ii/rdiiResult/page.tsx @@ -77,8 +77,8 @@ const Result = () => { const [resetSelection, setResetSelection] = useState(false); const [isResetPage, setIsResetPage] = useState(false); const [curPage, setCurPage] = useState(1); // 현재 페이지 - const [ctpvCd, setCtpvCd] = useState(0); // 시도 코드 상태 - const [sggCd, setSggCd] = useState(0); // 시군구 코드 상태 + const [ctpvCd, setCtpvCd] = useState('0'); // 시도 코드 상태 + const [sggCd, setSggCd] = useState('0'); // 시군구 코드 상태 const [sggName, setSggName] = useState(''); // 시군구 이름 상태 const {ctpv, sgg} = useStore(); @@ -112,8 +112,8 @@ const Result = () => { const inftwtAnlsSearchDto = { aplcnYmFrom: formValues.aplcnYmFrom?.trim() ? formValues.aplcnYmFrom : null, aplcnYmTo: formValues.aplcnYmTo?.trim() ? formValues.aplcnYmTo : null, - ctpvCd: ctpvCd || null, - sggCd: sggCd || null, + ctpvCd: ctpvCd !== '0' ? ctpvCd.trim() : null, + sggCd: sggCd !== '0' ? sggCd : null, swtrmtFcltNm: formValues.swtrmtFcltNm?.trim() ? formValues.swtrmtFcltNm : null, auth: AUTH, }; @@ -140,15 +140,15 @@ const Result = () => { const dataWithRowNumber = (data.content || []).map((item: any, index: number) => { // 🎯 먼저 각 아이템을 포맷팅 const formattedItem = formatDisplayData(item); - const ctpvOne = ctpv.find(code => code.id === item.ctpvCd); - const sggOne = sgg.find(code => code.id === item.sggCd); + const ctpvOne = ctpv.find(code => code.val.trim() === item.ctpvCd.trim()); + const sggOne = sgg.find(code => code.val === item.sggCd); // 추가 처리 및 일련번호 추가 return { ...formattedItem, rowNumber: (curPage - 1) * 10 + index + 1, // 1부터 시작하는 일련번호 추가 scsYn: item.scsYn === null || item.scsYn === undefined ? 'N' : item.scsYn, // scsYn이 null이면 'N'으로 변경 - ctpvNm: ctpvOne ? ctpvOne.name : item.ctpvCd, - sggNm: sggOne ? sggOne.name : item.sggCd, + ctpvNm: ctpvOne ? ctpvOne.text.trim() : item?.ctpvCd?.trim(), + sggNm: sggOne ? sggOne.text : item.sggCd, }; }) .filter((item: any) => item.scsYn === 'Y'); diff --git a/apps/sn/app/(with-base-layout)/ii/result/page.tsx b/apps/sn/app/(with-base-layout)/ii/result/page.tsx index 6e929933a..8df0a60a8 100644 --- a/apps/sn/app/(with-base-layout)/ii/result/page.tsx +++ b/apps/sn/app/(with-base-layout)/ii/result/page.tsx @@ -74,8 +74,8 @@ const Result = () => { const [resetSelection, setResetSelection] = useState(false); const [isResetPage, setIsResetPage] = useState(false); const [curPage, setCurPage] = useState(1); // 현재 페이지 - const [ctpvCd, setCtpvCd] = useState(0); // 시도 코드 상태 - const [sggCd, setSggCd] = useState(0); // 시군구 코드 상태 + const [ctpvCd, setCtpvCd] = useState('0'); // 시도 코드 상태 + const [sggCd, setSggCd] = useState('0'); // 시군구 코드 상태 const [sggName, setSggName] = useState(''); // 시군구 이름 상태 const {ctpv, sgg} = useStore(); @@ -106,8 +106,8 @@ const Result = () => { let inftwtAnlsSearchDto = { "aplcnYmFrom": formValues.aplcnYmFrom && formValues.aplcnYmFrom !== '' ? formValues.aplcnYmFrom : null, "aplcnYmTo": formValues.aplcnYmTo && formValues.aplcnYmTo !== '' ? formValues.aplcnYmTo : null, - "ctpvCd": ctpvCd === 0 ? null : ctpvCd, - "sggCd": sggCd === 0 ? null : sggCd, + "ctpvCd": ctpvCd === '0' ? null : ctpvCd.trim(), + "sggCd": sggCd === '0' ? null : sggCd, "swtrmtFcltNm": formValues.swtrmtFcltNm?.trim() ? formValues.swtrmtFcltNm : null, "auth": AUTH, }; @@ -135,15 +135,15 @@ const Result = () => { const dataWithRowNumber = (data.content || []).map((item: any, index: number) => { // 🎯 먼저 각 아이템을 포맷팅 const formattedItem = formatDisplayData(item); - const ctpvOne = ctpv.find(code => code.id === item.ctpvCd); - const sggOne = sgg.find(code => code.id === item.sggCd); + const ctpvOne = ctpv.find(code => code.val.trim() === item?.ctpvCd?.trim()); + const sggOne = sgg.find(code => code.val === item.sggCd); // 추가 처리 및 일련번호 추가 return { ...formattedItem, rowNumber: (curPage - 1) * 10 + index + 1, // 1부터 시작하는 일련번호 추가 scsYn: item.scsYn === null || item.scsYn === undefined ? 'N' : item.scsYn, // scsYn이 null이면 'N'으로 변경 - ctpvNm: ctpvOne ? ctpvOne.name : item.ctpvCd, - sggNm: sggOne ? sggOne.name : item.sggCd, + ctpvNm: ctpvOne ? ctpvOne.text : item.ctpvCd, + sggNm: sggOne ? sggOne.text : item.sggCd, }; }) .filter((item: any) => item.scsYn === 'Y'); diff --git a/apps/sn/app/components/ui/ctpvSggPrcsFcltSelectBox.tsx b/apps/sn/app/components/ui/ctpvSggPrcsFcltSelectBox.tsx index 9b9df0724..66d5722d8 100644 --- a/apps/sn/app/components/ui/ctpvSggPrcsFcltSelectBox.tsx +++ b/apps/sn/app/components/ui/ctpvSggPrcsFcltSelectBox.tsx @@ -43,6 +43,8 @@ export function CtpvSggPrcsFcltSelectBox({ const [prcsFcltOptions, setPrcsFcltOptions] = useState([]); const { ctpv, sgg } = useStore(); + const sidoStr = String(sido ?? ''); + const sidoPrefix = sidoStr.slice(0, 2); useEffect(() => { (async () => { @@ -129,7 +131,7 @@ export function CtpvSggPrcsFcltSelectBox({ className="w-48" selectClass="w-48 rounded-lg bg-white truncate" label="" - selectArray={[defaultOption, ...sgg.filter(opt => opt.val.startsWith(sido.slice(0, 2)))]} + selectArray={[defaultOption, ...sgg.filter(opt => opt.val.startsWith(sidoPrefix))]} value={sigungu} onSelectValue={val => { onSigunguChange(String(val)) From 579e599eb1b2cc04f00cc978ae7069efd37c7b2e Mon Sep 17 00:00:00 2001 From: swcho Date: Mon, 11 Aug 2025 18:23:05 +0900 Subject: [PATCH 04/12] =?UTF-8?q?feat=20searchBar=20=EC=8B=9C=EC=84=A4?= =?UTF-8?q?=EB=AA=85=20=EA=B0=80=EB=82=98=EB=8B=A4=20=EC=88=9C=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=A0=95=EB=A0=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/ui/map/searchBar/procSearchBar.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/common/business_components/src/ui/map/searchBar/procSearchBar.tsx b/packages/common/business_components/src/ui/map/searchBar/procSearchBar.tsx index dbded59af..3604dbcf8 100644 --- a/packages/common/business_components/src/ui/map/searchBar/procSearchBar.tsx +++ b/packages/common/business_components/src/ui/map/searchBar/procSearchBar.tsx @@ -144,7 +144,9 @@ export const ProcSearchBar = ({ gisMaps, facilityTypes }: SearchBarProps) => { })); } - setFacilityData([{ text: "시도", val: "0" }, ...list]); + // 가나다순 정렬 후 set + const sorted = list.slice().sort((a, b) => a.text.localeCompare(b.text, 'ko')); + setFacilityData([{ text: "시도", val: "0" }, ...sorted]); setFacilityValue("0"); }; From a91b2d2c360cd294dd139d1f6050615ecece11e9 Mon Sep 17 00:00:00 2001 From: swcho Date: Mon, 11 Aug 2025 18:27:57 +0900 Subject: [PATCH 05/12] =?UTF-8?q?fix:=20trim()=20=EC=97=90=EB=9F=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 --- apps/sn/app/(with-base-layout)/ii/rdiiResult/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/sn/app/(with-base-layout)/ii/rdiiResult/page.tsx b/apps/sn/app/(with-base-layout)/ii/rdiiResult/page.tsx index 257916d76..354467d9d 100644 --- a/apps/sn/app/(with-base-layout)/ii/rdiiResult/page.tsx +++ b/apps/sn/app/(with-base-layout)/ii/rdiiResult/page.tsx @@ -140,7 +140,7 @@ const Result = () => { const dataWithRowNumber = (data.content || []).map((item: any, index: number) => { // 🎯 먼저 각 아이템을 포맷팅 const formattedItem = formatDisplayData(item); - const ctpvOne = ctpv.find(code => code.val.trim() === item.ctpvCd.trim()); + const ctpvOne = ctpv.find(code => code.val.trim() === item?.ctpvCd?.trim()); const sggOne = sgg.find(code => code.val === item.sggCd); // 추가 처리 및 일련번호 추가 return { From 6d768432f88029b990d044c3f3d1f761911aa99f Mon Sep 17 00:00:00 2001 From: swcho Date: Tue, 12 Aug 2025 09:20:20 +0900 Subject: [PATCH 06/12] =?UTF-8?q?refactor:=20=EC=B2=98=EB=A6=AC=EA=B5=AC?= =?UTF-8?q?=EC=97=AD=20=EA=B0=92=20=EC=97=86=EC=9D=84=20=EB=95=8C=20'-'?= =?UTF-8?q?=EB=A1=9C=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/sn/app/(map-layout)/map/components/common/table.ts | 3 ++- apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/sn/app/(map-layout)/map/components/common/table.ts b/apps/sn/app/(map-layout)/map/components/common/table.ts index 238ba7599..c8c9deaed 100644 --- a/apps/sn/app/(map-layout)/map/components/common/table.ts +++ b/apps/sn/app/(map-layout)/map/components/common/table.ts @@ -33,6 +33,7 @@ export const MsSwagePplCol2 = [ { id: 'instMngNo', title: '기관\n관리번호' }, { id: 'ctpvNm', title: '시도' }, { id: 'sggNm', title: '시군구' }, + { id: "swtrmt_zone_nm", title: "처리구역" }, { id: 'instlYmd', title: '설치일자' }, // { id: 'mapshtNo', title: '도엽번호' }, { id: 'usgCd', title: '용도' }, @@ -660,7 +661,7 @@ export const dateFields = [ // 🎯 camelCase 버전 추가 'instlYmd', 'lastDrdgnYmd', 'cmcnYmd', 'oprtngStrtYmd', 'clsgYmd', 'mesureBeginDt', 'mesureEndDt', 'qltwtrBeginDt', 'qltwtrEndDt', - 'rainBeginDt', 'rainEndDt', + 'rainBeginDt', 'rainEndDt', 'flfmtBgngYmd', 'flfmtEndYmd', 'flfmtYr' ]; diff --git a/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx b/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx index ccce61561..be64dbe37 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx @@ -228,6 +228,7 @@ const SearchModal: React.FC = ({ usgCd: usgCdObj ? usgCdObj.text : item.usgCd, ctpvNm, sggNm, + swtrmt_zone_nm: item.swtrmtZoneNm || item.swtrmt_zone_nm || '-', }; }); From fa7a7d1bd96756920af47b644e5519f9b206d10f Mon Sep 17 00:00:00 2001 From: swcho Date: Tue, 12 Aug 2025 09:45:48 +0900 Subject: [PATCH 07/12] =?UTF-8?q?fix:=20-=20=EC=B9=A8=EC=9E=85=EC=88=98=20?= =?UTF-8?q?=EB=B6=84=EC=84=9D,=20RDII=20=EB=B6=84=EC=84=9D=20=EC=8B=A4?= =?UTF-8?q?=ED=96=89=20=ED=9B=84=20=ED=95=98=EC=88=98=EC=B2=98=EB=A6=AC?= =?UTF-8?q?=EC=8B=9C=EC=84=A4=EB=AA=85=20=EC=95=88=20=EB=B3=B4=EC=9D=B4?= =?UTF-8?q?=EB=8A=94=20=EC=97=90=EB=9F=AC=20=EC=88=98=EC=A0=95=20-=20repor?= =?UTF-8?q?tTab.tsx=EC=97=90=20=EB=B6=88=ED=95=84=EC=9A=94=20log=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/sn/app/(map-layout)/map/searchModal/reportTab.tsx | 9 --------- apps/sn/app/(with-base-layout)/ii/BaseLayout.tsx | 4 ++-- apps/sn/app/(with-base-layout)/ii/irsetting/page.tsx | 6 ++++-- apps/sn/app/(with-base-layout)/ii/rdii/page.tsx | 2 +- apps/sn/app/components/ui/ctpvSggPrcsFcltSelectBox.tsx | 6 +++--- 5 files changed, 10 insertions(+), 17 deletions(-) diff --git a/apps/sn/app/(map-layout)/map/searchModal/reportTab.tsx b/apps/sn/app/(map-layout)/map/searchModal/reportTab.tsx index 20d9768a2..0682ce8f5 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/reportTab.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/reportTab.tsx @@ -100,7 +100,6 @@ const ReportTab: React.FC = ({ open, isSearch = true, ctpvNm, sg // 하수도정비기본계획 테이블 cellClick 핸들러 const handleReportCellClick = (index: number | undefined) => { - console.log(index); if (typeof index === "number" && tableData[index]) { const reportData = tableData[index]; const fileName = reportData.fileName; @@ -119,22 +118,14 @@ const ReportTab: React.FC = ({ open, isSearch = true, ctpvNm, sg try { const reportData = flattenFolders(reportOriginData); let filterReportData = reportData; - console.log("필터링 전 보고서 데이터:", filterReportData); - console.log('ctpv, sgg, ctpvCd, sggCd', ctpv, sgg, ctpvCd, sggCd); if (ctpvCd !== '0') { // 시도검색 - console.log('시도 실행되나'); - console.log('ctpvCd.trim()', ctpvCd.trim()); const sidoOption = ctpv.find((n) => n.val.trim() === ctpvCd.trim()); - console.log('sidoOption', sidoOption) filterReportData = filterReportData.filter(item => item.sido === sidoOption?.text); - console.log('시도 필터링 후:', filterReportData); } if (sggCd !== '0') { // 시군구검색 - console.log('시군구 실행되나'); const sigunguOption = sgg.find((n) => String(n.val) === String(sggCd)); filterReportData = filterReportData.filter(item => item.sigungu === sigunguOption?.text); - console.log('시군구 필터링 후:', filterReportData); } if (reportGubun !== "0") { // 보고서구분검색 const reportGubunOption = reportGubuns.find((n) => n.val === reportGubun); diff --git a/apps/sn/app/(with-base-layout)/ii/BaseLayout.tsx b/apps/sn/app/(with-base-layout)/ii/BaseLayout.tsx index 68f5ec068..bf056f4e7 100644 --- a/apps/sn/app/(with-base-layout)/ii/BaseLayout.tsx +++ b/apps/sn/app/(with-base-layout)/ii/BaseLayout.tsx @@ -43,8 +43,8 @@ type BaseLayout = { sggCd: string; sggName?: string; sigungu?: ApiSelectOption - selectedSwagePrcsFclt?: string | number; - onSwagePrcsFcltChange?: (value: string | number) => void; + selectedSwagePrcsFclt?: string; + onSwagePrcsFcltChange?: (value: string) => void; aplcnYmFrom?: string setAplcnYmFrom?: (aplcnYmFrom: string) => void; aplcnYmTo?: string diff --git a/apps/sn/app/(with-base-layout)/ii/irsetting/page.tsx b/apps/sn/app/(with-base-layout)/ii/irsetting/page.tsx index 90e9bd440..14a565851 100644 --- a/apps/sn/app/(with-base-layout)/ii/irsetting/page.tsx +++ b/apps/sn/app/(with-base-layout)/ii/irsetting/page.tsx @@ -45,7 +45,7 @@ const initialFileInfo: UploadedFileInfo = { file: null, atflCd: null, atflId: nu const IrSetting = () => { const [input1, setInput1] = useState('0.8'); // 오수전환율 초기값 const [input2, setInput2] = useState(''); - const [select1, setSelect1] = useState('0'); // 하수처리장코드 + const [select1, setSelect1] = useState('0'); // 하수처리장코드 const [formResetKey, setFormResetKey] = useState(0); // FileUploadForm 리셋을 위한 key 상태 const [isLoadingResult, setIsLoadingResult] = useState(false); // 로딩 상태 const [ctpvCd, setCtpvCd] = useState('0'); // 시도 코드 상태 @@ -111,7 +111,7 @@ const IrSetting = () => { setSelectedDate(`${year}${month}`); setInput1(''); // 입력 필드 초기화 setInput2(''); // 입력 필드 초기화 - setSelect1(0); + setSelect1('0'); setSwtrmtFcltNm(''); setFormResetKey(prevKey => prevKey + 1); // FileUploadForm 재마운트를 위해 key 변경 }; @@ -324,6 +324,8 @@ const IrSetting = () => { return; } } + // const handleAnalysisClick = () => { + // } return ( <> diff --git a/apps/sn/app/(with-base-layout)/ii/rdii/page.tsx b/apps/sn/app/(with-base-layout)/ii/rdii/page.tsx index aea5c873a..7354db6cd 100644 --- a/apps/sn/app/(with-base-layout)/ii/rdii/page.tsx +++ b/apps/sn/app/(with-base-layout)/ii/rdii/page.tsx @@ -107,7 +107,7 @@ export default function RTKForm() { initialFileInfo, // 2: 강우자료 ]); - const [select1, setSelect1] = useState('0'); // 하수처리장 (swtrmtFcltCd) + const [select1, setSelect1] = useState('0'); // 하수처리장 (swtrmtFcltCd) const [ctpvCd, setCtpvCd] = useState('0'); // 시도 코드 상태 const [sggCd, setSggCd] = useState('0'); // 시군구 코드 상태 const [sggName, setSggName] = useState(''); // 시군구 이름 상태 diff --git a/apps/sn/app/components/ui/ctpvSggPrcsFcltSelectBox.tsx b/apps/sn/app/components/ui/ctpvSggPrcsFcltSelectBox.tsx index 66d5722d8..73bf619b3 100644 --- a/apps/sn/app/components/ui/ctpvSggPrcsFcltSelectBox.tsx +++ b/apps/sn/app/components/ui/ctpvSggPrcsFcltSelectBox.tsx @@ -18,8 +18,8 @@ interface CtpvSggPrcsFcltSelectBoxProps { setCtpvName?: (name: string) => void; setSggName?: (name: string) => void; className?: string; - selectedSwagePrcsFclt?: string | number; - onSwagePrcsFcltChange?: (value: string | number) => void; + selectedSwagePrcsFclt?: string; + onSwagePrcsFcltChange?: (value: string) => void; setSwtrmtFcltNm?: (name: string) => void; setIsLoading?: (isLoading: boolean) => void; } @@ -150,7 +150,7 @@ export function CtpvSggPrcsFcltSelectBox({ selectArray={[defaultOption, ...prcsFcltOptions]} value={selectedSwagePrcsFclt} onSelectValue={(val) => { - onSwagePrcsFcltChange?.(val) + onSwagePrcsFcltChange?.(String(val)) if (setSwtrmtFcltNm) setSwtrmtFcltNm(prcsFcltOptions.find(opt => String(opt.val) === String(val))?.text || "") }} selectContentClass="z-[101]" From 7b6c2af463d6d5fb4df289c23e9103b992d862d9 Mon Sep 17 00:00:00 2001 From: swcho Date: Tue, 12 Aug 2025 10:10:21 +0900 Subject: [PATCH 08/12] =?UTF-8?q?fix:=20=EA=B8=B0=EB=B3=B8=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=ED=95=98=EC=88=98=EA=B4=80=EB=A1=9C=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=EB=84=88=EB=B9=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/sn/app/(map-layout)/map/searchModal/swagePpl.tsx | 2 +- apps/sn/app/components/ui/ctpvSggPrcsFcltSelectBox.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/sn/app/(map-layout)/map/searchModal/swagePpl.tsx b/apps/sn/app/(map-layout)/map/searchModal/swagePpl.tsx index 1676b469a..ee599887a 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/swagePpl.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/swagePpl.tsx @@ -80,7 +80,7 @@ const SwagePpl: React.FC = ({ {/* 용도 */} opt.val.startsWith(sidoPrefix))]} From bd7c5b4d50f069a880abca3e62cc8553caa42a35 Mon Sep 17 00:00:00 2001 From: swcho Date: Tue, 12 Aug 2025 10:39:26 +0900 Subject: [PATCH 09/12] =?UTF-8?q?fix:=20=EC=9A=B4=EC=98=81=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=A1=B0=ED=9A=8C=20=EA=B1=B4=EC=88=98=204?= =?UTF-8?q?=EA=B1=B4=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../map/searchModal/searchModal.tsx | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx b/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx index be64dbe37..48dc9ebfd 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx @@ -19,6 +19,8 @@ const TABS = [ { val: "report", text: "하수도정비기본계획보고서" }, ]; +const OPERATION_TABLE_SIZE = 4; + // 날짜 조합 함수 const getDateString = ( year: string, @@ -239,7 +241,7 @@ const SearchModal: React.FC = ({ } else if (activeTab === 'operation') { const RequestDTO: Record = { page: `${curPage - 1}`, - size: '5', + size: `${OPERATION_TABLE_SIZE}`, }; if (var1) RequestDTO.bizInfoNm = var1; if (var2 != '0' && var2) RequestDTO.bizTypeCd = var2; @@ -275,7 +277,7 @@ const SearchModal: React.FC = ({ const matched = BIZ_TY_CD.find(code => code.lwpoCd === item.bizTypeCd); return { ...formattedItem, - rowNumber: (curPage - 1) * 5 + index + 1, // 1부터 시작하는 일련번호 추가 + rowNumber: (curPage - 1) * OPERATION_TABLE_SIZE + index + 1, // 1부터 시작하는 일련번호 추가 bizTypeCd: matched ? matched.lwpoCdNm : item.bizTypeCd, }; }); @@ -491,8 +493,8 @@ const SearchModal: React.FC = ({ try { const RequestDTO: Record = { page: `${detailCurPage - 1}`, - size: '5', - bizId: tableData[index % 5].bizId, + size: `${OPERATION_TABLE_SIZE}`, + bizId: tableData[index % OPERATION_TABLE_SIZE].bizId, }; RequestDTO.workTypes = JSON.parse(workType.replace(/'/g, '"')); @@ -509,7 +511,7 @@ const SearchModal: React.FC = ({ const mqltCdObj = MS_SWAGE_PPL_CODES.find(code => code.val === item.mqltCd.trim()); return { ...formattedItem, - rowNumber: (detailCurPage - 1) * 5 + detailIndex + 1, + rowNumber: (detailCurPage - 1) * OPERATION_TABLE_SIZE + detailIndex + 1, usgCd: usgCdObj ? usgCdObj.text : item.usgCd, mqltCd: mqltCdObj ? mqltCdObj.text : item.mqltCd, }; @@ -535,7 +537,7 @@ const SearchModal: React.FC = ({ try { const RequestDTO: Record = { page: `${detailCurPage - 1}`, - size: '5', + size: `${OPERATION_TABLE_SIZE}`, bizId: String(detailBizId), }; const res = await getData(`v1/bizInfo/fclts?${new URLSearchParams(RequestDTO).toString()}`); @@ -547,7 +549,7 @@ const SearchModal: React.FC = ({ const mqltCdObj = MS_SWAGE_PPL_CODES.find(code => code.val === item.mqltCd.trim()); return { ...formattedItem, - rowNumber: (detailCurPage - 1) * 5 + detailIndex + 1, + rowNumber: (detailCurPage - 1) * OPERATION_TABLE_SIZE + detailIndex + 1, usgCd: usgCdObj ? usgCdObj.text : item.usgCd, mqltCd: mqltCdObj ? mqltCdObj.text : item.mqltCd, }; @@ -667,7 +669,7 @@ const SearchModal: React.FC = ({ } tableData={tableData} headlist={dynamicHeadlist} - pageSize={5} + pageSize={OPERATION_TABLE_SIZE} total={tableCount} cellClick={handleOperationCellClick} onPageChange={setCurPage} @@ -690,7 +692,7 @@ const SearchModal: React.FC = ({ } tableData={detailTableData} headlist={dynamicHeadlist2} - pageSize={5} + pageSize={OPERATION_TABLE_SIZE} total={detailTableCount} cellClick={undefined} onPageChange={setDetailCurPage} From cc1c8caeef79b5de2ce06fcb79423a0a69eb5194 Mon Sep 17 00:00:00 2001 From: ljpark Date: Tue, 12 Aug 2025 10:58:18 +0900 Subject: [PATCH 10/12] =?UTF-8?q?=EC=88=98=EC=9A=A9=EA=B0=80=20=EC=83=81?= =?UTF-8?q?=EC=88=98=EC=82=AC=EC=9A=A9=EB=9F=89=20upload?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../(with-base-layout)/ii/irsetting/page.tsx | 37 ++++++++++++++++--- .../app/components/lib/utils/excelToJson.ts | 19 ++++++++++ 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/apps/sn/app/(with-base-layout)/ii/irsetting/page.tsx b/apps/sn/app/(with-base-layout)/ii/irsetting/page.tsx index 14a565851..de187da5d 100644 --- a/apps/sn/app/(with-base-layout)/ii/irsetting/page.tsx +++ b/apps/sn/app/(with-base-layout)/ii/irsetting/page.tsx @@ -9,7 +9,7 @@ import { zodResolver } from '@hookform/resolvers/zod' import { useState } from 'react' import { useForm } from 'react-hook-form' import { z } from 'zod' -import { excelToFlowRateData, excelToMatchingResultData, excelToTimePatternData } from '@/components/lib/utils' +import { excelToFlowRateData, excelToMatchingResultData, excelToTimePatternData, excelToRcptrInfoData } from '@/components/lib/utils' import BaseLayout from '../BaseLayout' import { validateMultipleFiles, FILE_EXTENSIONS, type FileValidationConfig } from '../../fileValidation'; import { validateBasicSelectionsWithAlert } from '../../selectionValidation'; @@ -172,12 +172,14 @@ const IrSetting = () => { const file1 = uploadedFilesData[0]; // 오수관망도 const file2 = uploadedFilesData[1]; // 수용가-맨홀 매칭결과 const file3 = uploadedFilesData[2]; // 오수량 시간패턴 - const file4 = uploadedFilesData[3]; // 유량자료 + const file4 = uploadedFilesData[3]; // 유량자료 + const file5 = uploadedFilesData[4]; // 수용가 상수사용량 console.log("오수관망도 정보:", file1?.file); console.log("수용가-맨홀 매칭결과 정보:", file2); console.log("오수량 시간패턴 정보:", file3); console.log("유량자료 정보:", file4); + console.log("수용가 상수사용량 정보:", file5); // 모든 필수 파일이 선택되었는지 확인 (UploadedFileInfo 객체와 그 안의 file 객체 모두 확인) // 유량자료는 선택값 @@ -214,6 +216,14 @@ const IrSetting = () => { fileDescription: '유량자료' }); } + // 수용가 상수사용량 파일이 있는 경우 검증 목록에 추가 + if (file5?.file) { + validationConfigs.push({ + file: file5.file, + allowedExtensions: FILE_EXTENSIONS.EXCEL, + fileDescription: '수용가 상수사용량' + }); + } // 파일 확장자 검증 실행 const validationResult = validateMultipleFiles(validationConfigs); @@ -242,18 +252,22 @@ const IrSetting = () => { type MatchingResult = { anlsSn: number; mhlMngNo: string; rcptrNo: string; }; type TimePattern = { hrId: number; rt?: number | null | undefined; }; type FlowRate = { pplMngNo: string; mtrngDt: string; oilq?: number | null | undefined; }; + type rcptrInfo = { rcptrNo: string; useYm: string; usqty?: number | null | undefined; }; const filePickers: { file: UploadedFileInfo; - parser: (excelData: any) => MatchingResult[] | TimePattern[] | FlowRate[]; + parser: (excelData: any) => MatchingResult[] | TimePattern[] | FlowRate[] | rcptrInfo[]; }[] = [ { file: file2, parser: excelToMatchingResultData }, { file: file3, parser: excelToTimePatternData } ]; - if (file4?.file) { + if (file4?.file) { // 유량자료 파일이 있는 경우 filePickers.push({ file: file4, parser: excelToFlowRateData }); } + if (file5?.file) { // 수용가 상수사용량 파일이 있는 경우 + filePickers.push({ file: file5, parser: excelToRcptrInfoData }); + } try { const parsedResults = await Promise.all( @@ -290,6 +304,9 @@ const IrSetting = () => { const flowRateData = file4?.file ? parsedResults.find(r => r && r.fileName === file4.file?.name)?.parsedData : null; + const rcptrInfoData = file5?.file + ? parsedResults.find(r => r && r.fileName === file5.file?.name)?.parsedData + : null; // 새로운 JSON 데이터 생성 const combinedAnalysisData = { @@ -310,6 +327,7 @@ const IrSetting = () => { tbSnRcptrMhlMpng: matchingResultData, // 수용가-맨홀 매칭결과 tbSnHrPttn: timePatternData, // 오수량 시간패턴 tbSnOilqData: flowRateData, // 유량자료 (없을 수 있음) + tbSnRcptrInfo: rcptrInfoData, // 수용가 상수사용량 (없을 수 있음) }; console.log("통합 분석 데이터 (JSON):", combinedAnalysisData); @@ -326,7 +344,7 @@ const IrSetting = () => { } // const handleAnalysisClick = () => { // } - + const rcptrInfoShow = false; return ( <> @@ -390,6 +408,15 @@ const IrSetting = () => { startYear={1900} // 시작 연도 설정 /> + {rcptrInfoShow && + handleFileSelection(4, file, cd, id)} + showButton={false} + showPreview={true} + accept={".xls, .xlsx, .xlsm, .xltx"} + fileIdx={4} /> + } { return flowRateData; }; +// 수용가 물사용량 +export const rcptrInfoZod = z.object({ + rcptrNo: z.string(), // 수용가번호 + useYm: z.string(), // 사용연월 + usqty: z.number().nullish(), // 사용량(㎥) +}); +export type rcptrInfoZodType = z.infer; +export const excelToRcptrInfoData = (excelData: any) => { + const flowRateData: rcptrInfoZodType[] = excelData.map((item: any) => { + + return { + rcptrNo: String(item["수용가번호"]), + useYm: String(item["사용연월"]), + usqty: Number(item["사용량(㎥)"]), + }; + }).filter((el: any) => el !== undefined); + return flowRateData; +}; + // 강우자료 (수정 필요) export const rainZod = z.object({ From 8c79a13d3a9cfe220ed96a42e3a6d02e6168300c Mon Sep 17 00:00:00 2001 From: swcho Date: Tue, 12 Aug 2025 10:59:03 +0900 Subject: [PATCH 11/12] =?UTF-8?q?fix:=20-=20searchModal=20viewPort=20Max?= =?UTF-8?q?=EA=B0=92=20100=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95.=20-=20?= =?UTF-8?q?=EC=9A=B4=EC=98=81=EC=A0=95=EB=B3=B4=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EA=B1=B4=EC=88=98=205=EA=B0=9C=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx b/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx index 48dc9ebfd..d740505ce 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx @@ -19,7 +19,7 @@ const TABS = [ { val: "report", text: "하수도정비기본계획보고서" }, ]; -const OPERATION_TABLE_SIZE = 4; +const OPERATION_TABLE_SIZE = 5; // 날짜 조합 함수 const getDateString = ( @@ -713,7 +713,7 @@ const SearchModal: React.FC = ({ bodyClass={` h-[100vh] w-[60vw] - max-w-[60vw] + max-w-[100vw] max-h-[100vh] overflow-hidden z-[101] From 98d4de29382ef0b19c4f5e58f5ea3a38a7ce829c Mon Sep 17 00:00:00 2001 From: swcho Date: Tue, 12 Aug 2025 11:33:09 +0900 Subject: [PATCH 12/12] =?UTF-8?q?feat:=20=ED=95=98=EC=88=98=EB=A7=A8?= =?UTF-8?q?=ED=99=80,=20=ED=95=98=EC=88=98=ED=8E=8C=ED=94=84=EC=9E=A5,=20?= =?UTF-8?q?=EC=9A=B0=EC=88=98=ED=86=A0=EC=8B=A4=20=EC=8B=9C=EB=8F=84,=20?= =?UTF-8?q?=EC=8B=9C=EA=B5=B0=EA=B5=AC=20=EC=A1=B0=ED=9A=8C=20=EC=A1=B0?= =?UTF-8?q?=EA=B1=B4=20=EB=B0=8F=20=EC=BB=AC=EB=9F=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../map/components/common/table.ts | 18 +++++--- .../(map-layout)/map/searchModal/basicTab.tsx | 34 +++++++-------- .../map/searchModal/searchModal.tsx | 19 ++++++--- .../(map-layout)/map/searchModal/stofcbr.tsx | 41 ++++++++++++++----- .../(map-layout)/map/searchModal/swageMhl.tsx | 18 ++++++++ .../map/searchModal/swagePmstn.tsx | 27 ++++++++++-- 6 files changed, 117 insertions(+), 40 deletions(-) diff --git a/apps/sn/app/(map-layout)/map/components/common/table.ts b/apps/sn/app/(map-layout)/map/components/common/table.ts index c8c9deaed..31f9d6dfc 100644 --- a/apps/sn/app/(map-layout)/map/components/common/table.ts +++ b/apps/sn/app/(map-layout)/map/components/common/table.ts @@ -392,6 +392,8 @@ export const MsSwageMhlCol2 = [ // { id: 'geom', title: 'geometry' }, // { id: 'ftreSmbolCd', title: '지형지물부호코드' }, { id: 'fcltMngNo', title: '시설관리번호' }, + { id: 'ctpvNm', title: '시도' }, + { id: 'sggNm', title: '시군구' }, // { id: 'pbadmsEmdCd', title: '행정읍면동코드' }, // { id: 'mapshtNo', title: '도엽번호' }, // { id: 'mngInstCd', title: '관리기관코드' }, @@ -500,12 +502,14 @@ export const ExclnSewagePumpCol2 = [ // { id: 'geom', title: 'geometry' }, // { id: 'ftreSmbolCd', title: '지형지물부호코드' }, { id: 'fcltMngNo', title: '시설관리번호' }, + { id: 'ctpvNm', title: '시도' }, + { id: 'sggNm', title: '시군구' }, // { id: 'pbadmsEmdCd', title: '행정읍면동코드' }, // { id: 'mapshtNo', title: '도엽번호' }, // { id: 'mngInstCd', title: '관리기관코드' }, - { id: 'instlYmd', title: '설치일자' }, { id: 'swagePmstnNm', title: '하수펌프장명' }, - { id: 'pllnArea', title: '부지면적(m²)' }, + { id: 'instlYmd', title: '설치일자' }, + // { id: 'pllnArea', title: '부지면적(m²)' }, // { id: 'opngSttsCd', title: '개통상태코드' }, // { id: 'usgCd', title: '용도코드' }, { id: 'dailyPrcsCpct', title: '일일처리용량(㎥)' }, @@ -543,11 +547,13 @@ export const DrtwSewagePumpCol2 = [ // { id: 'ftreSmbolCd', title: '지형지물부호코드' }, { id: 'fcltMngNo', title: '시설관리번호' }, // { id: 'pbadmsEmdCd', title: '행정읍면동코드' }, - { id: 'mapshtNo', title: '도엽번호' }, + // { id: 'mapshtNo', title: '도엽번호' }, + { id: 'ctpvNm', title: '시도' }, + { id: 'sggNm', title: '시군구' }, // { id: 'mngInstCd', title: '관리기관코드' }, - { id: 'instlYmd', title: '설치일자' }, { id: 'swagePmstnNm', title: '하수펌프장명' }, - { id: 'pllnArea', title: '부지면적(m²)' }, + { id: 'instlYmd', title: '설치일자' }, + // { id: 'pllnArea', title: '부지면적(m²)' }, // { id: 'opngSttsCd', title: '개통상태코드' }, // { id: 'usgCd', title: '용도코드' }, { id: 'dailyPrcsCpct', title: '일일처리용량(㎥)' }, @@ -589,6 +595,8 @@ export const stofcbrCol2 = [ { id: 'fcltMngNo', title: '시설관리번호' }, // { id: 'pbadmsEmdCd', title: '행정읍면동코드' }, { id: 'mapshtNo', title: '도엽번호' }, + { id: 'ctpvNm', title: '시도' }, + { id: 'sggNm', title: '시군구' }, // { id: 'mngInstCd', title: '관리기관코드' }, { id: 'instlYmd', title: '설치일자' }, // { id: 'fcltyShpCd', title: '시설물형태코드' }, diff --git a/apps/sn/app/(map-layout)/map/searchModal/basicTab.tsx b/apps/sn/app/(map-layout)/map/searchModal/basicTab.tsx index 7a783f139..70cd18884 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/basicTab.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/basicTab.tsx @@ -7,6 +7,7 @@ import SwagePrcsFclt from './swagePrcsFclt'; import SwagePrcsZone from './swagePrcsZone'; import SwageMhl from './swageMhl'; import SwagePmstn from './swagePmstn'; +import Stofcbr from './stofcbr'; // 기본정보 '구분' 선택 목록 export const BASIC_TYPES = [ @@ -156,10 +157,14 @@ const BasicTab: React.FC = ({ var1={var1} start1={start1} end1={end1} + city={city} + sgg={sgg} yearFilter={yearFilter} setVar1={setVar1} setStart1={setStart1} setEnd1={setEnd1} + setCity={setCity} + setSgg={setSgg} setYearFilter={setYearFilter} handleSearch={handleSearch} /> @@ -171,33 +176,30 @@ const BasicTab: React.FC = ({ start2={start2} end1={end1} end2={end2} + city={city} + sgg={sgg} yearFilter={yearFilter} setStart1={setStart1} setStart2={setStart2} setEnd1={setEnd1} setEnd2={setEnd2} + setCity={setCity} + setSgg={setSgg} setYearFilter={setYearFilter} handleSearch={handleSearch} /> )} {/* 분기처리: 우수토실 */} {basicType === "tb_ms_stofcbr" && ( -
- {/* 설치년도 */} -
- setYearFilter({ ...yearFilter, start: range.start, end: range.end })} - startLabel="설치년도" - endLabel="" - /> - {/* 조회 버튼 */} -
- -
-
-
+ )}
); diff --git a/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx b/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx index d740505ce..7b813c48a 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/searchModal.tsx @@ -305,8 +305,8 @@ const SearchModal: React.FC = ({ // 추후 작성 예정 if (var1) cqlFilters.push(`usg_cd='${var1}'`); if (var2) cqlFilters.push(`mqlt_cd='${var2}'`); - if (ctpvCd !== '0') cqlFilters.push(`pbadms_emd_cd LIKE '${ctpvCd.trim()}%'`); if (ctpvCd !== '0' && sggCd !== '0') cqlFilters.push(`pbadms_emd_cd LIKE '${sggCd}%'`); + else if (ctpvCd !== '0') cqlFilters.push(`pbadms_emd_cd LIKE '${ctpvCd.trim()}%'`); // 설치년도 범위 const startDate = getDateString( yearFilter.start, @@ -383,6 +383,9 @@ const SearchModal: React.FC = ({ // 하수맨홀용 CQL 필터 생성 const mhCqlFilters = () => { const cqlFilters: string[] = []; + // 시도, 시군구 + if (ctpvCd !== '0' && sggCd !== '0') cqlFilters.push(`pbadms_emd_cd LIKE '${sggCd}%'`); + else if (ctpvCd !== '0') cqlFilters.push(`pbadms_emd_cd LIKE '${ctpvCd.trim()}%'`); // // 설치년도 범위 const startDate = getDateString( yearFilter.start, @@ -410,6 +413,9 @@ const SearchModal: React.FC = ({ // 하수펌프장용 CQL 필터 생성 const psmtnCqlFilters = () => { const cqlFilters: string[] = []; + // 시도, 시군구 + if (ctpvCd !== '0' && sggCd !== '0') cqlFilters.push(`pbadms_emd_cd LIKE '${sggCd}%'`); + else if (ctpvCd !== '0') cqlFilters.push(`pbadms_emd_cd LIKE '${ctpvCd.trim()}%'`); // 설치년도 범위 const startDate = getDateString( yearFilter.start, @@ -442,6 +448,9 @@ const SearchModal: React.FC = ({ // 우수토실용 CQL 필터 생성 const otflCqlFilters = () => { const cqlFilters: string[] = []; + // 시도, 시군구 + if (ctpvCd !== '0' && sggCd !== '0') cqlFilters.push(`pbadms_emd_cd LIKE '${sggCd}%'`); + else if (ctpvCd !== '0') cqlFilters.push(`pbadms_emd_cd LIKE '${ctpvCd.trim()}%'`); // 설치년도 범위 const startDate = getDateString( yearFilter.start, @@ -711,10 +720,10 @@ const SearchModal: React.FC = ({ open={open} onOpenChange={onOpenChange} bodyClass={` - h-[100vh] - w-[60vw] - max-w-[100vw] - max-h-[100vh] + h-[100dvh] + w-[60dvw] + max-w-[100dvw] + max-h-[100dvh] overflow-hidden z-[101] `} diff --git a/apps/sn/app/(map-layout)/map/searchModal/stofcbr.tsx b/apps/sn/app/(map-layout)/map/searchModal/stofcbr.tsx index 700d60cf0..2e4fd26f0 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/stofcbr.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/stofcbr.tsx @@ -3,32 +3,53 @@ import { YearRangeSelectBox } from '@/components/ui/YearRangeSelectBox'; import { Button } from '@common/components'; import React from 'react'; +import { CtpvSggPrcsFcltSelectBox } from '@/components/ui/ctpvSggPrcsFcltSelectBox'; interface StofcbrProps { + city: string; + sgg: string; yearFilter: { start: string; end: string }; + setCity: (value: string) => void; + setSgg: (value: string) => void; setYearFilter: (filter: { start: string; end: string }) => void; handleSearch: () => void; } const Stofcbr: React.FC = ({ + city, + sgg, yearFilter, + setCity, + setSgg, setYearFilter, handleSearch, }) => { return (
- {/* 설치년도 */}
- setYearFilter({ ...yearFilter, start: range.start, end: range.end })} - startLabel="설치년도" - endLabel="" + {/* 시도, 시군구 */} + { + setCity(sidoId); + setSgg("0"); + }} + onSigunguChange={setSgg} /> - {/* 조회 버튼 */} -
- + {/* 설치년도 */} +
+ setYearFilter({ ...yearFilter, start: range.start, end: range.end })} + startLabel="설치년도" + endLabel="" + /> + {/* 조회 버튼 */} +
+ +
diff --git a/apps/sn/app/(map-layout)/map/searchModal/swageMhl.tsx b/apps/sn/app/(map-layout)/map/searchModal/swageMhl.tsx index 0951ceb2f..6face5b38 100644 --- a/apps/sn/app/(map-layout)/map/searchModal/swageMhl.tsx +++ b/apps/sn/app/(map-layout)/map/searchModal/swageMhl.tsx @@ -5,16 +5,21 @@ import { Button, Input, Label } from '@common/components'; import React from 'react'; import { MS_SWAGE_MHL_USE_CODES } from '../components/common/table'; import { SelectBox } from '@common/business_components/ui'; +import { CtpvSggPrcsFcltSelectBox } from '@/components/ui/ctpvSggPrcsFcltSelectBox'; interface SwageMhlProps { var1: string; start1: string; end1: string; + city: string; + sgg: string; yearFilter: { start: string; end: string }; setVar1: (value: string) => void; setStart1: (value: string) => void; setEnd1: (value: string) => void; + setCity: (value: string) => void; + setSgg: (value: string) => void; setYearFilter: (filter: { start: string; end: string }) => void; handleSearch: () => void; } @@ -23,10 +28,14 @@ const SwageMhl: React.FC = ({ var1, start1, end1, + city, + sgg, yearFilter, setVar1, setStart1, setEnd1, + setCity, + setSgg, setYearFilter, handleSearch, }) => { @@ -34,6 +43,15 @@ const SwageMhl: React.FC = ({ return (
+ { + setCity(sidoId); + setSgg("0"); + }} + onSigunguChange={setSgg} + /> {/* 설치년도 */} void; setStart2: (value: string) => void; setEnd1: (value: string) => void; setEnd2: (value: string) => void; + setCity: (value: string) => void; + setSgg: (value: string) => void; setYearFilter: (filter: { start: string; end: string }) => void; handleSearch: () => void; } @@ -23,11 +28,15 @@ const SwagePmstn: React.FC = ({ start2, end1, end2, + city, + sgg, yearFilter, setStart1, setStart2, setEnd1, setEnd2, + setCity, + setSgg, setYearFilter, handleSearch, }) => { @@ -35,6 +44,16 @@ const SwagePmstn: React.FC = ({ return (
+ {/* 시도, 시군구 */} + { + setCity(sidoId); + setSgg("0"); + }} + onSigunguChange={setSgg} + /> {/* 설치년도 */} = ({ startLabel="설치년도" endLabel="" /> - {/* 일일처리용량 - 오수맨홀 */} + {/* 일일처리용량 */} = ({ } }} /> - {/* 양수능력 - 우수맨홀 */} - + {/* 양수능력 */} + {/* = ({ handleSearch(); } }} - /> + /> */} {/* 조회 버튼 */}