wr: 하수재이용시설 조회 api 정리2
This commit is contained in:
+2
-2
@@ -13,8 +13,8 @@ NEXT_PUBLIC_CS_SERVER_API_URL = http://dev.onasys.co.kr:8000
|
||||
NEXT_PUBLIC_CS_TUS_UPLOAD = /attach-service/api/v1/tus/upload
|
||||
NEXT_PUBLIC_GEOSERVER_URL = https://hasudo.geo.rsonesoft.com/geoserver
|
||||
NEXT_PUBLIC_LX_GEOSERVER_URL = http://con.mind-one.co.kr:11306/geoserver
|
||||
# NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11083/reuse-service/api/v1
|
||||
NEXT_PUBLIC_WR_SERVER_API_URL = http://localhost:8883/reuse-service/api/v1
|
||||
NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11083/reuse-service/api/v1
|
||||
# NEXT_PUBLIC_WR_SERVER_API_URL = http://localhost:8883/reuse-service/api/v1
|
||||
NEXT_PUBLIC_SEWERAGE_API_URL = http://con.mind-one.co.kr:11083/sewerage-service # 개발 서버 API
|
||||
# NEXT_PUBLIC_SEWERAGE_API_URL=http://localhost:8883/sewerage-service
|
||||
NEXT_PUBLIC_NGII_URL = https://map.ngii.go.kr
|
||||
|
||||
@@ -46,7 +46,8 @@ export const mapService = {
|
||||
return response.json();
|
||||
},
|
||||
getPbnstRuseFclts: async (ruseFcltPk:any) => {
|
||||
const response = await fetch(`${DEV_URL_WR}/reuseFc/pubFc/${ruseFcltPk}`, {
|
||||
const year = new Date().getFullYear();
|
||||
const response = await fetch(`${DEV_URL_WR}/reuseFc/pubFc/${ruseFcltPk}?year=${year}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
|
||||
@@ -2,7 +2,8 @@ import { getFetch, postFectch, fetchType } from "@/components/lib/api";
|
||||
|
||||
const fetchpbnstDetail = async (featureCd: string, setTabData: any) => {
|
||||
try {
|
||||
const response = await getFetch("wr", `/reuseFc/pubFc/${featureCd}`);
|
||||
const year = new Date().getFullYear();
|
||||
const response = await getFetch("wr", `/reuseFc/pubFc/${featureCd}?year=${year}`);
|
||||
// 중복 데이터 추가 방지
|
||||
setTabDataFunc(response, featureCd, setTabData);
|
||||
} catch (error) {
|
||||
@@ -55,4 +56,4 @@ const detainSttn = async (featureCd: string, layerNm: string) => {
|
||||
}
|
||||
}
|
||||
|
||||
export { fetchHasuDetail, fetchpbnstDetail, detainSttn };
|
||||
export { fetchHasuDetail, fetchpbnstDetail, detainSttn };
|
||||
|
||||
@@ -126,10 +126,10 @@ export default function PbnstSttn() {
|
||||
(index: number | undefined) => {
|
||||
if (index !== undefined && pbnstSttnRes && pbnstSttnRes[index]) {
|
||||
const pbnstRuseFcltId = pbnstSttnRes[index].pbnstRuseFcltId;
|
||||
getPbnStnDetail(pbnstRuseFcltId);
|
||||
getPbnStnDetail(pbnstRuseFcltId, searchYear);
|
||||
}
|
||||
},
|
||||
[getPbnStnDetail, pbnstSttnRes]
|
||||
[getPbnStnDetail, pbnstSttnRes, searchYear]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -11,6 +11,36 @@ import type { ReturnType } from "@common/business_components/ui";
|
||||
import type { customPbnst, pubHasuType } from "../../ruseFcltMng/fcltReg/pbnstReg/type";
|
||||
import { excelPbnstSttnParsing } from "../../ruseFcltMng/fcltSttn/pbnstSttn/excel";
|
||||
|
||||
const getCurrentYear = () => String(new Date().getFullYear());
|
||||
|
||||
const sumPrfUsage = (prfList: FcPrfType["prfList"] = []) => {
|
||||
return prfList.reduce(
|
||||
(acc, cur) => {
|
||||
acc.inUsage +=
|
||||
cur.wshwtr +
|
||||
cur.coolUswtr +
|
||||
cur.cleanUswtr +
|
||||
cur.drwtUswtr +
|
||||
cur.dltnUswtr +
|
||||
cur.ithlRswtr +
|
||||
cur.ithlEtcUswtr;
|
||||
acc.outUsage +=
|
||||
cur.cleanToilUswtr +
|
||||
cur.resn +
|
||||
cur.lndwtr +
|
||||
cur.hydUswtr +
|
||||
cur.ugwtChr +
|
||||
cur.farmUswtr +
|
||||
cur.rvrKeepUswtr +
|
||||
cur.indstUswtr;
|
||||
acc.total = acc.inUsage + acc.outUsage;
|
||||
|
||||
return acc;
|
||||
},
|
||||
{ total: 0, inUsage: 0, outUsage: 0 }
|
||||
);
|
||||
};
|
||||
|
||||
export const ruseMapSize = 15;
|
||||
export type ruseMapState = {
|
||||
ruseMap: {
|
||||
@@ -147,10 +177,10 @@ const hasuListFetch = async (
|
||||
cur.drwtUswtr +
|
||||
cur.dltnUswtr +
|
||||
cur.ithlRswtr +
|
||||
cur.ithlEtcUswtr +
|
||||
cur.cleanToilUswtr +
|
||||
cur.resn;
|
||||
cur.ithlEtcUswtr;
|
||||
acc.outUsage +=
|
||||
cur.cleanToilUswtr +
|
||||
cur.resn +
|
||||
cur.lndwtr +
|
||||
cur.hydUswtr +
|
||||
cur.ugwtChr +
|
||||
@@ -247,22 +277,12 @@ export const ruseMapActionsExport: (set: any) => ruseMapActions = (
|
||||
try {
|
||||
const ruseDetailList = await getFetch(
|
||||
fetchType.WR,
|
||||
`/reuseFc/pubFc/${bscFctCd}`
|
||||
);
|
||||
const year = new Date().getFullYear();
|
||||
const data = [bscFctCd];
|
||||
const rusePrfList = await postFectch(
|
||||
`/reuseFc/pubDetailList/${year}/0/1/10`,
|
||||
data,
|
||||
fetchType.WR
|
||||
`/reuseFc/pubFc/${bscFctCd}?year=${getCurrentYear()}`
|
||||
);
|
||||
const dataList = ruseDetailList.map((ruse) => {
|
||||
const matchRuse = rusePrfList?.data.find(
|
||||
(prf) => prf.pbnstRuseFcltId === ruse.pbnstRuseFcltId
|
||||
);
|
||||
return {
|
||||
...ruse,
|
||||
prfList: matchRuse.prfList,
|
||||
prfList: ruse.prfList ?? [],
|
||||
};
|
||||
});
|
||||
console.log("/dataList ", dataList);
|
||||
@@ -331,51 +351,13 @@ export const ruseMapActionsExport: (set: any) => ruseMapActions = (
|
||||
try {
|
||||
const ruseDetailList = await getFetch(
|
||||
fetchType.WR,
|
||||
`/reuseFc/pubFc/${bscFctCd}`
|
||||
);
|
||||
const year = new Date().getFullYear();
|
||||
const data = [bscFctCd];
|
||||
const rusePrfList = await postFectch(
|
||||
`/reuseFc/pubDetailList/${year}/0/1/10`,
|
||||
data,
|
||||
fetchType.WR
|
||||
`/reuseFc/pubFc/${bscFctCd}?year=${getCurrentYear()}`
|
||||
);
|
||||
const dataList = ruseDetailList.map((ruse) => {
|
||||
const matchRuse = rusePrfList?.data.find(
|
||||
(prf) => prf.pbnstRuseFcltId === ruse.pbnstRuseFcltId
|
||||
);
|
||||
|
||||
|
||||
const usage = matchRuse.prfList.reduce(
|
||||
(acc, cur) => {
|
||||
acc.inUsage +=
|
||||
cur.wshwtr +
|
||||
cur.coolUswtr +
|
||||
cur.cleanUswtr +
|
||||
cur.drwtUswtr +
|
||||
cur.dltnUswtr +
|
||||
cur.ithlRswtr +
|
||||
cur.ithlEtcUswtr +
|
||||
cur.cleanToilUswtr +
|
||||
cur.resn;
|
||||
acc.outUsage +=
|
||||
cur.lndwtr +
|
||||
cur.hydUswtr +
|
||||
cur.ugwtChr +
|
||||
cur.farmUswtr +
|
||||
cur.rvrKeepUswtr +
|
||||
cur.indstUswtr;
|
||||
acc.total = acc.inUsage + acc.outUsage;
|
||||
|
||||
return acc;
|
||||
},
|
||||
{ total: 0, inUsage: 0, outUsage: 0 }
|
||||
);
|
||||
|
||||
|
||||
const usage = sumPrfUsage(ruse.prfList ?? []);
|
||||
return {
|
||||
...ruse,
|
||||
prfList: matchRuse.prfList,
|
||||
prfList: ruse.prfList ?? [],
|
||||
inUsage: usage?.inUsage,
|
||||
outUsage: usage?.outUsage,
|
||||
|
||||
|
||||
@@ -152,7 +152,8 @@ const hasuListFetch = async (
|
||||
};
|
||||
|
||||
const initFetch = async (ruseFcltPk: string | undefined) => {
|
||||
const pbnstRes = await getFetch("wr", `/reuseFc/pubFc/${ruseFcltPk}`);
|
||||
const year = new Date().getFullYear();
|
||||
const pbnstRes = await getFetch("wr", `/reuseFc/pubFc/${ruseFcltPk}?year=${year}`);
|
||||
return pbnstRes;
|
||||
};
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ type pbnstSttnActions = {
|
||||
searchNm: string | undefined,
|
||||
year: string
|
||||
) => void;
|
||||
getPbnStnDetail: (pbnstRuseFcltId: string) => void;
|
||||
getPbnStnDetail: (pbnstRuseFcltId: string, year: string) => void;
|
||||
resetPbnstDetail: () => void;
|
||||
};
|
||||
|
||||
@@ -187,7 +187,6 @@ export const pbnstListFetch = async (
|
||||
rprtvBzenty: item.rprtvBzenty || "-",
|
||||
bgngDt: item.bgngDt || "",
|
||||
endDt: item.endDt || "",
|
||||
prfList: item.prfList ?? [],
|
||||
};
|
||||
});
|
||||
|
||||
@@ -267,17 +266,18 @@ export const pbnstSttnActionsExport: (set: any) => pbnstSttnActions = (
|
||||
});
|
||||
},
|
||||
//하수처리시설을 조회하여 하수재이용시설을 조회한다.
|
||||
getPbnStnDetail: async (pbnstRuseFcltId: string) => {
|
||||
getPbnStnDetail: async (pbnstRuseFcltId: string, year: string) => {
|
||||
try {
|
||||
let pbnstDetail = await getFetch(
|
||||
const pbnstDetailList = await getFetch(
|
||||
"wr",
|
||||
`/reuseFc/pubFc/${pbnstRuseFcltId}`
|
||||
`/reuseFc/pubFc/${pbnstRuseFcltId}?year=${year}`
|
||||
);
|
||||
if (pbnstDetail.length >= 0) {
|
||||
pbnstDetail = pbnstDetail.find(
|
||||
(item: customPbnst) => item.pbnstRuseFcltId === pbnstRuseFcltId
|
||||
);
|
||||
}
|
||||
const pbnstDetail = Array.isArray(pbnstDetailList)
|
||||
? pbnstDetailList.find(
|
||||
(item: customPbnst) => item.pbnstRuseFcltId === pbnstRuseFcltId
|
||||
)
|
||||
: undefined;
|
||||
console.log(pbnstDetail);
|
||||
set((state: pbnstSttnState) => {
|
||||
return {
|
||||
...state,
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import type { PrfType } from "@/app/store/prfmncReg/pbnstPrfmncReg/type";
|
||||
|
||||
export type WaterReuseFacility = {
|
||||
swtrmtFcltId?: string;
|
||||
bscFctNm: string; // 기본시설명 (예: "난지")
|
||||
@@ -24,5 +22,4 @@ export type WaterReuseFacility = {
|
||||
rprtvBzenty: string;
|
||||
bgngDt: string;
|
||||
endDt: string;
|
||||
prfList:PrfType[];
|
||||
};
|
||||
|
||||
@@ -228,26 +228,8 @@ export function PbnstSttnModal({ data, isMap }: { data: customPbnst; isMap?: boo
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
if(isMap){
|
||||
if(data.prfList &&data.prfList.length>0){
|
||||
getTablePrfData(data.prfList);
|
||||
}else{
|
||||
getTablePrfData([]);
|
||||
}
|
||||
}else{
|
||||
|
||||
if (pbnstSttn.pbnstSttnRes && data) {
|
||||
const prfList = pbnstSttn.pbnstSttnRes.find(
|
||||
(item) => item.pbnstRuseFcltId === data.pbnstRuseFcltId
|
||||
)?.prfList;
|
||||
|
||||
if (prfList) {
|
||||
|
||||
getTablePrfData(prfList);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [pbnstSttn.pbnstSttnRes, data,isMap]);
|
||||
getTablePrfData(data.prfList ?? []);
|
||||
}, [data]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -0,0 +1,371 @@
|
||||
# 하수재이용시설 현황 API 정리 작업계획
|
||||
|
||||
작성일: 2026-07-01
|
||||
|
||||
## 1. 배경
|
||||
|
||||
현재 하수재이용시설 현황/상세 조회는 백엔드와 프런트 모두에서 응답 구조가 과도하게 분산되어 있다.
|
||||
|
||||
- 상세 조회는 `GET /reuseFc/pubFc/{pbnstRuseFcltId}` 호출 후, 다시 `POST /reuseFc/pubDetailList/...`를 추가 호출해서 실적을 붙이고 있다.
|
||||
- 현황 목록은 `GET /reuseFc/pbnstList/...` 호출 시 월별 실적 내역 `prfList`까지 함께 조회한 뒤, 서비스 레이어에서 장내/장외/총합계를 계산하고 있다.
|
||||
- 프런트도 위 구조에 맞춰 상세 모달과 현황 화면에서 중복 후처리를 수행한다.
|
||||
|
||||
이번 작업의 목표는 아래 2가지다.
|
||||
|
||||
1. `GET /reuseFc/pubFc/{pbnstRuseFcltId}` 단일 호출만으로 상세 모달에 필요한 데이터가 모두 내려오도록 정리
|
||||
2. `GET /reuseFc/pbnstList/...`는 목록에 필요한 합계만 SQL에서 계산해 내려주고, 월별 실적 내역 `prfList`는 제외
|
||||
|
||||
추가 전제:
|
||||
|
||||
- 본 작업은 backend 정리 후 이에 맞춰 `frontend`도 함께 수정한다.
|
||||
|
||||
## 2. 현재 구조 분석
|
||||
|
||||
### 2.1 상세 조회 API
|
||||
|
||||
현재 백엔드 상세 조회 엔드포인트:
|
||||
|
||||
- `GET /reuseFc/pubFc/{pbnstRuseFcltId}`
|
||||
|
||||
현재 SQL/매핑:
|
||||
|
||||
- `public_fc_select.xml`의 `getFc`
|
||||
- `PublicFcInsertResultMap`
|
||||
|
||||
현재 `getFc`는 아래 성격의 데이터만 내려준다.
|
||||
|
||||
- 기본 시설 정보
|
||||
- 파일 정보
|
||||
- 사업 정보
|
||||
- 운영 정보
|
||||
- 원수 취수 정보
|
||||
- 공급관로 정보
|
||||
- 수요처 정보
|
||||
|
||||
현재 `prfList`는 포함하지 않는다.
|
||||
|
||||
### 2.2 상세 실적 추가 조회 API
|
||||
|
||||
현재 추가 호출 엔드포인트:
|
||||
|
||||
- `POST /reuseFc/pubDetailList/{year}/{sggCd}/{pageNo}/{pageCnt}`
|
||||
|
||||
현재 역할:
|
||||
|
||||
- 시설 목록 기준으로 `prfList`를 포함한 실적 정보를 별도 조회
|
||||
- 프런트에서 `pubFc/{id}` 결과와 `pubDetailList` 결과를 다시 매핑
|
||||
|
||||
### 2.3 상세 모달 사용 위치 분석
|
||||
|
||||
실제 상세 모달 렌더링 위치는 아래 2곳이다.
|
||||
|
||||
- `apps/wr/components/ui/map/detailPopup/ruseDetailPopup.tsx`
|
||||
- `apps/wr/components/ui/modal/sttn/pbnstSttnModal/pbnstSttnModal.tsx`
|
||||
|
||||
추가 영향 지점은 아래와 같다.
|
||||
|
||||
- `apps/wr/app/store/map/ruseMap/index.tsx`
|
||||
- `getRuseMaplList()`
|
||||
- `getRuseMaplListReturn()`
|
||||
- 현재 `pubFc/{id}` 호출 후 `pubDetailList`를 다시 호출해 `prfList`를 수동 병합
|
||||
|
||||
- `apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/index.tsx`
|
||||
- `getPbnStnDetail()`
|
||||
- 현재는 `pubFc/{id}`만 조회하지만, 모달 내부는 상황에 따라 목록의 `prfList`를 참조
|
||||
|
||||
정리하면, 상세 모달 렌더링 지점은 2곳이 맞고, 실제 수정 범위는 스토어까지 확장된다.
|
||||
|
||||
### 2.4 현황 목록 API
|
||||
|
||||
현재 목록 엔드포인트:
|
||||
|
||||
- `GET /reuseFc/pbnstList/{year}/{pageNo}/{pageCnt}/{searchingCd}/{nameCd}/{fcltCpct}/{oprtngSttsCd}/{bscFctClsCd}`
|
||||
|
||||
현재 구조:
|
||||
|
||||
- SQL `getPbnstList`에서 `tb_wr_pbnst_ruse_fclt_prfmnc`를 조인
|
||||
- `PublicPrfListMap`으로 월별 `prfList`까지 전부 매핑
|
||||
- `PublicFcService.getPbnstList()`에서 `sumUsage()`로 장내/장외/총합 계산
|
||||
- 응답 객체 `PublicPbnstList`에 `prfList`도 포함
|
||||
|
||||
문제점:
|
||||
|
||||
- 목록 조회인데 월별 실적 상세까지 매번 로딩
|
||||
- 페이지 목록 응답에 비해 payload가 과다
|
||||
- 서비스 레이어에서 반복 합계 계산 수행
|
||||
- 프런트는 목록 화면에서 합계만 사용하지만 상세 내역까지 수신
|
||||
|
||||
## 3. 목표 구조
|
||||
|
||||
### 3.1 상세 조회 목표
|
||||
|
||||
`GET /reuseFc/pubFc/{pbnstRuseFcltId}` 한 번으로 아래가 모두 내려오도록 변경한다.
|
||||
|
||||
- 기본 시설 정보
|
||||
- 파일/사업/운영/원수취수/공급관로/수요처 정보
|
||||
- 해당 시설의 하수재이용실적 `prfList`
|
||||
- 필요 시 장내/장외/총합도 함께 포함 여부 검토
|
||||
|
||||
프런트는 상세 모달 진입 시 더 이상 `POST /reuseFc/pubDetailList/...`를 호출하지 않도록 변경한다.
|
||||
|
||||
### 3.2 목록 조회 목표
|
||||
|
||||
`GET /reuseFc/pbnstList/...`는 아래만 내려오도록 정리한다.
|
||||
|
||||
- 시설 기본 정보
|
||||
- 운영정보 1건
|
||||
- 장내 합계
|
||||
- 장외 합계
|
||||
- 총합계
|
||||
|
||||
제외 대상:
|
||||
|
||||
- 월별 실적 상세 `prfList`
|
||||
|
||||
합계는 SQL에서 계산한다.
|
||||
|
||||
## 4. 백엔드 작업계획
|
||||
|
||||
### 4.1 `GET /reuseFc/pubFc/{pbnstRuseFcltId}` 응답 확장
|
||||
|
||||
대상 파일:
|
||||
|
||||
- `wr_back_out/src/main/resources/postgres/mapper/wr/public_fc_select.xml`
|
||||
- `wr_back_out/src/main/java/kr/co/mindone/wrout/object/publicFc/PublicFcInsert.java` 대신 PublicFcSelect.java 로 신규 object생성
|
||||
- `wr_back_out/src/main/java/kr/co/mindone/wrout/controller/PublicFcController.java`
|
||||
- `wr_back_out/src/main/java/kr/co/mindone/wrout/service/public_fc/PublicFcService.java`
|
||||
|
||||
계획:
|
||||
|
||||
1. `getFc` SQL에 `tb_wr_pbnst_ruse_fclt_prfmnc` 조인 추가
|
||||
2. `year` query param을 추가하고, 해당 연도 실적만 조회하도록 수정
|
||||
3. frontend에서 상세 조회 시 현재년도를 세팅해서 호출
|
||||
|
||||
적용안:
|
||||
|
||||
- `GET /reuseFc/pubFc/{pbnstRuseFcltId}?year=2026`
|
||||
- frontend는 상세 모달 진입 시 `new Date().getFullYear()` 기준 현재년도를 세팅해서 호출
|
||||
- backend는 전달받은 `year` 기준으로 `prfList`를 조회
|
||||
|
||||
이유:
|
||||
|
||||
- 상세 모달은 현재 연도 기준 실적을 보는 흐름이 명확하다
|
||||
- 전체 연도 실적을 무제한 포함하면 payload가 다시 커진다
|
||||
- 실적 조회 기준 연도가 API 계약에 명시되어야 응답이 예측 가능하다
|
||||
|
||||
추가 검토:
|
||||
|
||||
- 현재 `getFc`는 `like #{fcltPk}||'%'`라서 같은 하수처리시설 하위 재이용시설 여러 건을 반환하는 구조다.
|
||||
- 호출명이 `/{pbnstRuseFcltId}` 이므로 실제 의도가
|
||||
- 특정 재이용시설 1건 조회인지
|
||||
- 기반 시설코드(prefix) 하위 재이용시설 다건 조회인지
|
||||
를 명확히 해야 한다.
|
||||
|
||||
현 프런트 사용상 분석:
|
||||
|
||||
- `ruseDetailPopup.tsx`는 탭으로 여러 재이용시설을 보여주므로 prefix 기반 다건 조회 구조를 활용 중이다.
|
||||
- `getPbnStnDetail()`는 정확한 `pbnstRuseFcltId`로 단건 선택 후 화면에서 1건 사용한다.
|
||||
|
||||
따라서 이번 변경에서는 기존 다건 반환 계약은 유지하되, 반환 각 항목에 `prfList`를 포함하는 쪽이 안전하다.
|
||||
|
||||
### 4.2 `pubDetailList` 영향 검토
|
||||
|
||||
현재 `pubDetailList`는 아래에서 사용된다.
|
||||
|
||||
- `apps/wr/app/store/map/ruseMap/index.tsx`
|
||||
- `hasuListFetch()`
|
||||
- `getRuseMaplList()`
|
||||
- `getRuseMaplListReturn()`
|
||||
- `packages/common/business_components/src/ui/map/searchBar/searchBar.tsx`
|
||||
- 경로 문자열 참조 1건
|
||||
- 과거 실적등록 관련 코드/문서
|
||||
|
||||
계획:
|
||||
|
||||
- 이번 작업에서 상세 모달 경로는 `pubFc/{id}` 단일 조회로 전환
|
||||
- `pubDetailList`는 잔여 런타임 사용처가 확인되었으므로 즉시 제거하지 않는다
|
||||
- 1차로 상세 모달 경로에서 제거하고, `ruseMap` 목록/지도 경로는 영향도 확인 후 후속 정리한다
|
||||
- 작업계획 기준으로는 "상세 모달에서는 더 이상 사용하지 않음"까지를 1차 목표로 둔다
|
||||
|
||||
### 4.3 `GET /reuseFc/pbnstList/...` SQL 합계화
|
||||
|
||||
대상 파일:
|
||||
|
||||
- `public_fc_select.xml`
|
||||
- `PublicPbnstList.java`
|
||||
- `PublicPrfListMap` 및 관련 DTO
|
||||
- `PublicFcService.getPbnstList()`
|
||||
|
||||
계획:
|
||||
|
||||
1. `getPbnstList` SQL에서 `prfList` 월별 내역 컬럼 제거
|
||||
2. 연도 조건이 반영된 실적 집계 서브쿼리 또는 집계 조인 추가
|
||||
3. SQL에서 아래 컬럼 직접 계산
|
||||
- `in_usage`
|
||||
- `out_usage`
|
||||
- `usage_total`
|
||||
4. 서비스 레이어 `sumUsage()` 기반 계산 제거
|
||||
5. `PublicPbnstList`에서 `prfList` 제거
|
||||
|
||||
- `pbnstList`는 현황 목록 용도
|
||||
- `pubFc/{id}`는 상세 용도
|
||||
- 응답 목적이 달라 DTO를 분리하는 편이 유지보수에 유리
|
||||
|
||||
### 4.4 서비스 레이어 정리
|
||||
|
||||
`PublicFcService.getPbnstList()`에서는 아래를 제거할 수 있다.
|
||||
|
||||
- `item.setPrfList(detail.getPrfList())`
|
||||
- `sumUsage(...)` 연쇄 호출
|
||||
|
||||
남는 역할:
|
||||
|
||||
- SQL 결과를 DTO로 변환
|
||||
- 운영정보 1건 정리
|
||||
- 기본 문자열 보정
|
||||
|
||||
## 5. 프런트 작업계획
|
||||
|
||||
### 5.1 상세 모달 경로 정리
|
||||
|
||||
대상 파일:
|
||||
|
||||
- `apps/wr/components/ui/map/detailPopup/ruseDetailPopup.tsx`
|
||||
- `apps/wr/components/ui/modal/sttn/pbnstSttnModal/pbnstSttnModal.tsx`
|
||||
- `apps/wr/app/store/map/ruseMap/index.tsx`
|
||||
- `apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/index.tsx`
|
||||
- `apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/type.tsx`
|
||||
|
||||
계획:
|
||||
|
||||
1. `ruseMap.getRuseMaplList()`에서 `pubDetailList` 추가 호출 제거
|
||||
2. `pubFc/{id}` 응답만으로 `ruseDetailList` 구성
|
||||
3. `PbnstSttnModal`이 `isMap` 여부에 따라 목록 `prfList`를 다시 참조하는 구조 단순화
|
||||
4. 상세 모달 공통 데이터 타입에 `prfList`가 항상 포함되도록 정리
|
||||
5. 상세 조회 호출 시 frontend에서 현재년도를 query param으로 전달
|
||||
|
||||
목표:
|
||||
|
||||
- 상세 모달 렌더링 시 실적 데이터 원천을 `pubFc/{id}` 하나로 통일
|
||||
|
||||
### 5.2 현황 목록 경로 정리
|
||||
|
||||
대상 파일:
|
||||
|
||||
- `apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/index.tsx`
|
||||
- 관련 화면:
|
||||
- `apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/pbnstSttn/page.tsx`
|
||||
|
||||
계획:
|
||||
|
||||
1. `pbnstListFetch()`가 `pbnstList` 응답의 `inUsage/outUsage/usageTotal`만 사용하도록 정리
|
||||
2. 목록 응답에서 `prfList`를 기대하는 코드 제거
|
||||
3. 상세 버튼 클릭 시 목록 데이터가 아니라 상세 API 응답을 기준으로 모달 표시
|
||||
|
||||
## 6. 데이터 구조 변경 계획
|
||||
|
||||
### 6.1 상세 응답
|
||||
|
||||
현재 후보:
|
||||
|
||||
- `PublicFcInsert` 확장
|
||||
- 또는 `PublicFcDetailWithPrf` 신규 DTO 추가
|
||||
|
||||
권장:
|
||||
|
||||
- 신규 상세 DTO 분리 검토
|
||||
|
||||
이유:
|
||||
|
||||
- 등록/수정용 DTO와 조회용 DTO 성격이 다름
|
||||
- 상세 조회에 `prfList`, 합계 필드, 화면 전용 값이 추가될 가능성이 높음
|
||||
|
||||
### 6.2 목록 응답
|
||||
|
||||
현재 `PublicPbnstList`는 `prfList`를 포함한다.
|
||||
|
||||
변경 방향:
|
||||
|
||||
- 목록 DTO에서는 `prfList` 제거
|
||||
- 합계 숫자 필드만 유지
|
||||
|
||||
프런트 타입도 이에 맞춰 변경:
|
||||
|
||||
- `WaterReuseFacility`
|
||||
- `customPbnst`
|
||||
- `FcPrfType` 사용 위치 재점검
|
||||
|
||||
## 7. 구현 순서
|
||||
|
||||
1. `pubFc/{id}` 응답에 실적 포함 설계 확정
|
||||
2. 상세 모달 사용처 2곳 및 스토어를 `pubFc/{id}` 단일 호출 구조로 전환
|
||||
3. `pbnstList` SQL을 합계형 목록 조회로 변경
|
||||
4. 목록 DTO 및 프런트 타입 정리
|
||||
5. 잔여 `pubDetailList` 사용처 영향 확인
|
||||
6. 화면 수동 검증
|
||||
|
||||
## 8. 검증 계획
|
||||
|
||||
### 8.1 상세 모달 검증
|
||||
|
||||
- 지도 팝업 상세
|
||||
- `ruseDetailPopup.tsx`
|
||||
- 현황 목록 상세 모달
|
||||
- `pbnstSttnModal.tsx`
|
||||
|
||||
확인 항목:
|
||||
|
||||
- `pubFc/{id}` 1회 호출만 발생하는지
|
||||
- 추가 `pubDetailList` 호출이 사라졌는지
|
||||
- 실적 탭의 장내/장외/합계 표가 기존과 동일하게 보이는지
|
||||
|
||||
### 8.2 목록 검증
|
||||
|
||||
- `pbnstList` 응답에서 `prfList`가 제거되었는지
|
||||
- `inUsage`, `outUsage`, `usageTotal` 합계가 기존과 동일한지
|
||||
- 검색/페이징/시도시군구 조건에서 정상 조회되는지
|
||||
|
||||
## 9. 리스크 및 확인 필요사항
|
||||
|
||||
### 9.1 `pubFc/{id}`의 조회 단위
|
||||
|
||||
현재 `getFc` SQL은 prefix 조회다.
|
||||
|
||||
- `WHERE pf.pbnst_ruse_fclt_id like #{fcltPk} || '%'`
|
||||
|
||||
이 계약을 유지할지,
|
||||
정확한 ID 단건 조회로 바꿀지 먼저 결정이 필요하다.
|
||||
|
||||
현 프런트와의 호환성을 고려하면 1차는 prefix 다건 조회 유지가 안전하다.
|
||||
|
||||
### 9.2 실적 연도 파라미터
|
||||
|
||||
상세 응답에 실적을 포함할 때 연도 조건은 필요하다.
|
||||
|
||||
이번 계획에서는 아래처럼 확정한다.
|
||||
|
||||
- `getFc` 조회 시 `year` query param을 받는다
|
||||
- frontend는 상세 실적 조회 시 현재년도를 세팅해서 호출한다
|
||||
- backend는 해당 연도 실적만 `prfList`에 포함한다
|
||||
|
||||
### 9.3 `pubDetailList` 잔여 사용처
|
||||
|
||||
상세 모달 외에도 아래 스토어에서 여전히 사용 중이다.
|
||||
|
||||
- `apps/wr/app/store/map/ruseMap/index.tsx`
|
||||
|
||||
이번 작업에서 상세 경로는 정리하되, 다른 화면의 잔여 사용 여부는 후속 정리 대상으로 남을 수 있다.
|
||||
|
||||
## 10. 결론
|
||||
|
||||
이번 작업은 단순 API 이름 정리가 아니라,
|
||||
|
||||
- 상세 조회는 `pubFc/{id}` 중심
|
||||
- 목록 조회는 `pbnstList` 중심
|
||||
|
||||
으로 응답 책임을 다시 나누는 작업이다.
|
||||
|
||||
핵심은 아래 두 줄로 요약된다.
|
||||
|
||||
1. 상세 모달은 `GET /reuseFc/pubFc/{pbnstRuseFcltId}` 한 번만 호출해도 되게 만든다.
|
||||
2. 목록 API `GET /reuseFc/pbnstList/...`는 월별 내역을 빼고 SQL 합계만 내려주게 정리한다.
|
||||
Reference in New Issue
Block a user