Compare commits

...
160 Commits
Author SHA1 Message Date
swcho 738b1f7735 Merge branch 'main' into iipbs/sn/ii 2025-09-30 15:44:57 +09:00
swcho b64ba3b343 fix: 운영환경 PROXY_HOST 수정 (http -> https) 2025-09-30 15:42:45 +09:00
swcho 3381e16573 chmod: 로그인 URL 변경 (localhost -> 원앤올 개발서버) 2025-09-29 17:46:58 +09:00
ljpark b73490ebc1 운영환경 수정 2025-09-26 17:13:14 +09:00
swcho 662e44b19a Merge branch 'iipbs/wr/dev' 2025-09-25 17:14:19 +09:00
swcho d12cae1e65 Merge branch 'iipbs/wr/drgtPopup' into iipbs/wr/dev 2025-09-25 17:13:45 +09:00
swcho f002c05292 chmod: drgtSttn (가뭄지도 패키지 경로 변경) 2025-09-25 17:13:12 +09:00
swcho e41dd0539a Merge branch 'iipbs/fo/dev' 2025-09-25 13:13:06 +09:00
swcho bf1c2a3300 fix: 빌드 에러 수정 (타입 에러) 2025-09-25 13:12:47 +09:00
swcho e6ddcfca57 Merge branch 'iipbs/fo/dev' 2025-09-25 11:33:17 +09:00
swcho aa4dc99f30 chore: colspan -> colSpan 대소문자 수정 2025-09-25 11:33:04 +09:00
swcho a3daa72bc8 Merge branch 'iipbs/fo/dev' 2025-09-25 11:27:12 +09:00
swcho 1a9ec5450c fix:
- 처리시설 시설정보 모달에서 '시설용량' 표출 에러 수정
- 시설 기본정보 테이블에서 '시설 구분' 컬럼 주석 처리
2025-09-25 11:26:05 +09:00
swcho 1b57670830 test: 메인 페이지 차트 컴포넌트 테스트 구현 2025-09-24 14:47:51 +09:00
jcchoi 3fbf9d0850 Merge branch 'main' of https://www.onasys.co.kr:3000/ONAANDALL/frontend 2025-09-24 10:39:05 +09:00
jcchoi 375397de2e 대시보드 기능 추가가 2025-09-24 10:39:01 +09:00
swcho 960227d8dd Merge branch 'iipbs/sn/dev' 2025-09-24 09:24:06 +09:00
swcho 00a8165476 remove, fix:
- CLAIM_NAME 삭제
- LOGIN_PAGE_URL Default 값 설정
2025-09-24 09:23:21 +09:00
leedj312 8d68fe652a Merge commit 'c853163d99fb858a65d05a5e990192bfc52d3602' 2025-09-23 14:12:55 +09:00
mind-one003 7f1f1933b5 Merge branch 'iipbs/fo/dev' 2025-09-23 14:08:52 +09:00
mind-one003 c6d7564eb9 Merge branch 'iipbs/common/main' into iipbs/fo/dev 2025-09-23 14:07:05 +09:00
mind-one003 c72fa450bc 엑셀다운로드 자연수까지 나오도록 array추가 2025-09-23 14:06:45 +09:00
mind-one003 5952760b05 빌드에러 수정, 유량현황 엑셀다운로드 수정 2025-09-23 14:06:18 +09:00
swcho 6c022cd1ec feat: 로그인 세션 만료시 CM 로그인 페이지로 리다이렉트 처리 (env 파일 도메인 재설정 필요) 2025-09-23 11:35:18 +09:00
leedj312 c853163d99 대민 현황 데이터 api 수정 적용 2025-09-23 11:10:37 +09:00
mind-one003 1b2da753a1 Merge branch 'iipbs/common/main' into iipbs/fo/dev 2025-09-23 11:07:35 +09:00
mind-one003 400d6cf732 엑셀 숫자형식 다운로드 추가 2025-09-23 11:07:23 +09:00
mind-one003 0929fe0674 다운로드 숫자로 변경 및 숫자 형식 지정하여 엑셀다운로드 지정할 수 있도록 수정 2025-09-23 11:07:01 +09:00
swcho c54381ae71 Merge branch 'iipbs/wr/dev' 2025-09-22 17:27:16 +09:00
swcho 0a2284138c remove: updateRainDetail, setUpdateRSwtDetail 초기화 로직 삭제 (중복) 2025-09-22 17:26:49 +09:00
swcho 536f07a13f Merge branch 'iipbs/wr/drgtPopup' into iipbs/wr/dev 2025-09-22 17:23:28 +09:00
swcho bf3ced7a00 fix: 하수재이용시설등록 페이지 계통도, 평면도 pdf만 업로드 되도록 수정 2025-09-22 17:20:19 +09:00
leedj312 0d9ebcbd55 로그인 사용자 건축물 등록 시도코드 적용/ 하수처리장 지도PopUp data 오류 슈ㅜ정/지도점검 오류 수정 2025-09-22 17:17:30 +09:00
swcho 46b1482e01 Merge branch 'iipbs/wr/dev' 2025-09-22 15:41:34 +09:00
swcho 64e5c4c0fb fix: 지도점검결과 등록 페이지 updateRainDetail 초기화 에러 수정 2025-09-22 15:39:19 +09:00
swcho 29e8223efa fix:
- 오타수정(upadateData -> updateData)
- 등록 후 셀 선택 초기화 에러 수정
2025-09-22 14:01:58 +09:00
swcho d12610db98 fix: 지도점검결과 등록 토스트 메세지 오타 수정 2025-09-22 13:49:01 +09:00
swcho 824ad72dfe Merge branch 'iipbs/wr/dev' 2025-09-22 09:56:33 +09:00
swcho ab0d787615 Merge branch 'iipbs/common/main' into iipbs/wr/drgtPopup 2025-09-22 09:54:50 +09:00
swcho 39e2734a49 fix: searchBar.tsx 하수처리시설 검색 에러 수정 2025-09-22 09:54:35 +09:00
swcho bc016c71ae refactor: drgtSttn(가뭄정보) 페이지 패키지 경로 변경 2025-09-22 09:53:56 +09:00
swcho 1c24065c6e Merge branch 'iipbs/sn/dev' 2025-09-19 18:12:00 +09:00
swcho 0995e6e43b docs: 하수관로 주석 API 추가 2025-09-19 18:09:47 +09:00
swcho cbc83207df Merge branch 'iipbs/sn/dev' 2025-09-18 18:16:20 +09:00
swcho 4610f671b1 fix, refactor:
- 하수도정비기본계획보고서 모달 표출 에러 수정
- import 경로 수정
2025-09-18 18:15:46 +09:00
swcho 884af91733 Merge branch 'main' of https://www.onasys.co.kr:3000/ONAANDALL/frontend 2025-09-18 14:23:19 +09:00
swcho baa7e71ba6 Merge branch 'iipbs/sn/dev' 2025-09-18 14:23:16 +09:00
mind-one003 b4e72a02e4 Merge branch 'iipbs/fo/dev' 2025-09-18 14:21:10 +09:00
leedj312 cee4073cf2 Merge commit '77b4ba01b458e05cf4b3f025d78b17f4d94e0853' 2025-09-18 14:19:57 +09:00
swcho ac29217256 refactor: console.log 삭제 및 정리 (필요한 로그는 있음) 2025-09-18 14:16:43 +09:00
leedj312 77b4ba01b4 물재이용 주석 추가중 2025-09-18 14:09:55 +09:00
swcho 8e8c18c1fc docs: 하수관로 파일 주석 추가 2025-09-18 14:06:41 +09:00
mind-one003 6c5cd9d1e0 페이지 주석 추가 2025-09-18 14:02:00 +09:00
mind-one003 9c36553e77 Merge branch 'iipbs/fo/dev' 2025-09-18 10:58:51 +09:00
leedj312 eac09bde2e Merge commit '311ce14fc97c833c99b69cd6ba928150ecda80c6' 2025-09-17 18:04:03 +09:00
leedj312 ebd2a9f2c8 Merge commit '6844db4c295b7ceab1ffe49255630ad90082edb7' 2025-09-17 18:03:33 +09:00
leedj312 41b90bd7b5 수요처 등록 컴포넌트 파라미터 추가 2025-09-17 18:03:20 +09:00
leedj312 6844db4c29 대민 수요처 등록 파라미터 추가 2025-09-17 17:52:52 +09:00
leedj312 311ce14fc9 물재이용 업무 대민 주소검색 컴포넌트 사용 x 2025-09-17 17:32:03 +09:00
leedj312 3c5d37cc6c 온배수 시설 수정 , 주석 삭제 2025-09-17 17:00:02 +09:00
mind-one003 adacc5fe33 빌드에러 수정 2025-09-17 16:18:48 +09:00
mind-one003 52b380a088 Merge branch 'iipbs/common/main' into iipbs/fo/dev 2025-09-17 16:15:34 +09:00
mind-one003 d92d4d3949 - 테이블 비율 고정 변수 추가(wideFixed)
- store headerlist 에서 비율 변수 추가(widePercent)
2025-09-17 16:15:11 +09:00
mind-one003 68ee60e252 테이블 간격 퍼센트로 조정, 인수인계 md추가 2025-09-17 16:12:47 +09:00
leedj312 858a2c0bac 물재이용 아이디별 지자체 코드 적용 실적 완료 2025-09-16 17:22:33 +09:00
leedj312 0bc87e2082 물재이용 로그인한 사용자의 시군구 코드에 따른 코드값 변경 (시설물 등록 부분만 완료) 2025-09-16 15:25:08 +09:00
leedj312 5588eddbc5 테이블 헤드 기호 추가 및 버튼 위치 수정 2025-09-16 10:13:35 +09:00
leedj312 682cc1297c 지도점검 엑셀 등록시 lodingbar추가 2025-09-15 17:45:22 +09:00
leedj312 e26d800449 통계 수정 2025-09-15 16:23:47 +09:00
leedj312 e6be168d0d 물재이용 공통코드 작업 수정 사항 추가 2025-09-15 15:38:25 +09:00
leedj312 ad6e4484b7 물재이용 공통코드 작업 2025-09-15 15:36:56 +09:00
leedj312 92f12c2104 공통코드 작업 완료/ 지도점검 등록/현황 페이지 수정 2025-09-12 17:29:34 +09:00
mind-one003 c17da82661 미처리하수량 제거(주석포함), 강우량 메인,모달 수치 다른거 해결 2025-09-12 13:54:20 +09:00
mind-one005 75d2d0c827 Merge branch 'main' of https://www.onasys.co.kr:3000/ONAANDALL/frontend 2025-09-11 12:42:55 +09:00
mind-one005 675a1a09fa /api/proxy 미들웨어 추가 2025-09-11 12:42:23 +09:00
mind-one003 372843a083 Merge branch 'iipbs/common/main' into iipbs/fo/dev 2025-09-11 11:19:40 +09:00
mind-one003 b93efa5503 라인바, 라인차트 x축 라벨 크기 확대 2025-09-11 11:17:37 +09:00
mind-one003 32939d8b1a 대시보드 총인설비 계산 로직 추가 2025-09-11 11:15:58 +09:00
swcho 00b0832acb Merge branch 'iipbs/sn/dev' 2025-09-10 15:30:26 +09:00
swcho 6e109e970e refactor:
- SearchModal 껐다 킬 때 페이지네이션 정보 잃어버리는 에러 수정
- useSearchModal.ts useEffect 의존성 배열을 searchModal.tsx 로 이동
- import 정리
2025-09-10 15:24:24 +09:00
mind-one003 8b2efad803 -주석 style적용 방식 수정
-대시보드, rdii조회 rdi계산 원본값에서 반올림한 후 계산되도록 수정
2025-09-09 14:46:11 +09:00
leedj312 00ecc1dc72 차트 데이터 , 제거 및 년도 공통 변수 처리 2025-09-09 13:39:34 +09:00
yschoi 328787e1b2 Merge branch 'main' of https://www.onasys.co.kr:3000/ONAANDALL/frontend 2025-09-09 10:39:27 +09:00
yschoi 1862497bf4 api url 수정 2025-09-09 10:38:11 +09:00
leedj312 344e77eafa Merge commit '500a6b1489456e94df84b590050d84c69fe200d3' 2025-09-09 10:12:05 +09:00
leedj312 1bf8afd9ac Merge commit 'c9169772922b9ad3046b894b4375f3983779a1bd' 2025-09-09 10:10:30 +09:00
leedj312 f50de19137 gis 오버레이 수정 2025-09-09 10:10:19 +09:00
swcho f9e8748906 Merge branch 'iipbs/sn/dev' 2025-09-09 09:59:41 +09:00
swcho 2f5d76ed38 Merge branch 'iipbs/common/main' into iipbs/sn/ii 2025-09-09 09:54:55 +09:00
swcho 0b8559891a remove: Gis.js에서 SearchView 컴포넌트 props 삭제 2025-09-09 09:54:40 +09:00
mind-one003 6df0f45fa3 하단주석 컴포넌트화 2025-09-08 18:03:47 +09:00
leedj312 c916977292 대민 물재이용 현황 데이터 받는걸로 수정 2025-09-08 17:42:50 +09:00
swcho d898121764 refactor, add:
- searchModal Store 패턴을 사용하여 상태 관리 및 UI, 비즈니스로직 분리
- tsconfig.json에 import paths 추가
2025-09-08 14:49:23 +09:00
mind-one003 79faffdfee 수질정보 모달 2021년이전 toc 대신 cod 데이터 보여지도록 수정 2025-09-05 17:55:05 +09:00
leedj312 500a6b1489 물재이용 지도 하수재이용 오버레이 변경 , 온배수 항목 추가 , 주소 검색 키 변수명 변경 2025-09-05 16:39:02 +09:00
mind-one003 28f495f11b Merge branch 'iipbs/common/main' into iipbs/fo/dev 2025-09-05 14:22:08 +09:00
mind-one003 ffa1781005 라인바 차트 좌측 여백 및 라벨 좌측으로 좀 더 이동 2025-09-05 14:21:39 +09:00
mind-one003 7fb9454c74 주요그래프 시설용량 > 지하수유입량 으로 수정 2025-09-05 14:17:23 +09:00
mind-one003 c05c7e6f41 Merge branch 'iipbs/common/main' into iipbs/fo/dev 2025-09-05 13:49:40 +09:00
mind-one003 b47c0dff2b 라인바 차트 크기 수정, custom left 축 만드는 로직 추가 2025-09-05 13:49:22 +09:00
leedj312 7e7335530e Merge commit '2d474696e6e5e648e940cf0ba6ec9153a32316f5' 2025-09-05 11:30:02 +09:00
leedj312 2d474696e6 대민 변경 2025-09-05 11:27:57 +09:00
yschoi a89eb98191 Merge remote-tracking branch 'origin/iipbs/fo/dev' 2025-09-05 09:24:16 +09:00
yschoi 2b28bae58f Merge remote-tracking branch 'origin/iipbs/wr/dev' 2025-09-05 09:23:18 +09:00
mind-one003 9fadb172f9 오타수정 2025-09-04 17:51:11 +09:00
mind-one003 99b0580697 총인시설 여부에 따라 총인시설 row 추가 혹은 제거 2025-09-04 15:30:31 +09:00
mind-one003 d9b52ba5ef rdi 조회화면과 대시보드의 rdii 값 맞춰주는 작업 진행 2025-09-04 14:52:26 +09:00
leedj312 cbc7c4918f 물재이용 사례관리 엑셀 등록 유효성 검사 및 저장 로직 변경 2025-09-04 14:43:29 +09:00
swcho 192cb91517 fix: sn/package.json에 xlsx 의존성 추가 (build 에러 수정) 2025-09-04 11:07:03 +09:00
yschoi ca45874fe9 Merge remote-tracking branch 'origin/iipbs/fo/dev' 2025-09-04 10:18:53 +09:00
yschoi d051d3fa1d Merge remote-tracking branch 'origin/iipbs/wr/dev' 2025-09-04 10:16:42 +09:00
swcho d99dbfee36 Merge remote-tracking branch 'origin/main' into iipbs/sn/dev 2025-09-04 09:44:06 +09:00
swcho ab6279a449 fix: 하수처리구역 시군구 매핑 에러 수정 2025-09-04 09:42:26 +09:00
leedj312 c4c5e68267 하수재이용 통계 매뉴 이동 수정 2025-09-03 17:55:05 +09:00
leedj312 5ec38f1fb4 Merge commit 'a03359540a57d48b8bc1af7ca8ccc2a232e2d12a' into iipbs/wr/dev 2025-09-03 16:28:21 +09:00
mind-one003 9707232954 총인시설 유무확인 로직 수정 - 데이터 들어올 시 확인필요 2025-09-03 15:18:31 +09:00
leedj312 d9cd742355 지도 팝업 데이터 없는경우 메시지 표출 2025-09-03 15:07:44 +09:00
swcho a26262d3b2 refactor: cql filter 각 파일로 이동 2025-09-03 14:20:31 +09:00
mind-one003 50b5c66a7e console.log 제거 2025-09-03 14:05:03 +09:00
mind-one003 b92baf8b2a 팝업 엑셀 다운로드 추가 2025-09-03 14:02:59 +09:00
mind-one003 236cc9fdd2 미처리하수량 주석추가 2025-09-02 17:18:19 +09:00
mind-one003 f923297498 Merge branch 'iipbs/common/main' into iipbs/fo/dev 2025-09-02 16:46:16 +09:00
mind-one003 83f5d878e7 라인바 y축 범위 수정 2025-09-02 16:44:43 +09:00
mind-one003 2f00efadfc - 미처리하수량 컬럼 추가
- 연 평균 > 연평균
2025-09-02 16:43:38 +09:00
mind-one003 34e88c6b63 날짜형식 오류 수정 2025-09-02 09:17:15 +09:00
mind-one003 c85147e989 Merge branch 'iipbs/common/main' into iipbs/fo/dev 2025-09-01 17:01:32 +09:00
mind-one003 e434e711bf 결함조치 하는중 2025-09-01 17:00:10 +09:00
mind-one003 03dd39b128 운영형상에 맞춰서 세팅 2025-08-29 15:32:02 +09:00
mind-one003 cfc4d70d43 Merge branch 'iipbs/common/main' into iipbs/fo/dev 2025-08-29 14:59:32 +09:00
mind-one003 ebe7d1a86c 주요그래프 총인유입tp 0이나 null인 경우 안보여지도록 수정(0으로 안나오도록..) 2025-08-29 14:55:55 +09:00
mind-one003 155f345911 강우일 운영현황 toBeInfoRnDay가 추가됨에 따른 로직 수정 2025-08-28 14:13:04 +09:00
mind-one003 a2a38f8937 강우영향일 로직수정
- changePart 제거
- 강우영향일 계산 후 강우일 담은 toBeInfoRnDay 변수 추가
2025-08-28 10:53:31 +09:00
mind-one003 1bfc8b6a19 계획하수량 산정지표현황
- 필요없는 콘솔제거
- 변동부하율 계산 수정
2025-08-28 09:34:47 +09:00
mind-one003 1cdbdd00d9 다운로드 엑셀 헤더에 단위 추가 2025-08-27 17:44:38 +09:00
mind-one003 eea932f43a Merge branch 'iipbs/common/main' into iipbs/fo/dev 2025-08-27 14:56:31 +09:00
mind-one003 5357a65b91 대시보드 tn,tp 불일치 수정 2025-08-27 09:55:42 +09:00
mind-one003 9d8678e8e5 Merge branch 'iipbs/common/main' into iipbs/fo/dev 2025-08-26 17:51:10 +09:00
mind-one003 03d5fc330a Merge branch 'iipbs/common/main' into iipbs/fo/dev 2025-08-26 17:48:11 +09:00
mind-one003 7ddb7dda97 라인바 차트property 추가 (setXAxisYearTick - 날짜 x축일경우 (년도-월)별로 만들어주는 속성) 2025-08-26 17:47:29 +09:00
mind-one003 2e6679c14f Merge branch 'iipbs/common/main' into iipbs/fo/dev 2025-08-26 17:39:23 +09:00
mind-one003 14c1846fe1 차트property 추가 (setXAxisYearTick - 날짜 x축일경우 (년도-월)별로 만들어주는 속성) 2025-08-26 17:38:25 +09:00
mind-one003 1600927237 팝업 데이터 포맷출력방식 변경 2025-08-26 14:05:39 +09:00
mind-one003 88893eb0be 에러수정 2025-08-26 13:33:18 +09:00
mind-one003 d3fa026e22 Merge branch 'iipbs/common/main' into iipbs/fo/dev 2025-08-26 13:31:21 +09:00
mind-one003 537c895ebe qltyDataSetting common index 로 이동 2025-08-26 11:24:39 +09:00
mind-one003 1b22d55b94 대시보드 수질현황 팝업과 데이터 맞추는 작업 완료 2025-08-26 11:19:29 +09:00
mind-one003 1fceb181b7 유량현황 데이터 맞추는 작업 완료 , 수질현황 작업진행 예정 2025-08-25 18:01:17 +09:00
mind-one003 aa54f32ba2 빌드에러 수정 2025-08-22 18:26:15 +09:00
mind-one003 bc5bce3171 대시보드 하절기 강우시 유입하수량 수정 완료 2025-08-22 18:23:31 +09:00
mind-one003 af8677d510 - 오수전환율 공통변수로 생성 - OSU_PERCENT
- CalcRainEffect 강우영향일만, 강우량만 계산되도록 파라미터 추가
2025-08-22 13:51:10 +09:00
mind-one003 8013483d17 대시보드 수치 맞추는 작업 진행중 (현재 유입유량 및 총유입량 맞추는 작업완료) 2025-08-21 18:27:52 +09:00
mind-one003 7ca09a60d8 -CalcRainEffect 강우량 자릿수 소수점 첫째자리 표시
- 수질현황 최대 최소 BOD, COD 수치 이상수정
2025-08-21 11:25:11 +09:00
mind-one003 f425a303e5 - 페이지에 산식 추가
- 오타수정
- CalcRainEffect에 강우량 x시 0.0으로 표시
2025-08-21 11:00:02 +09:00
mind-one003 fc70b9c4be CalcRainEffect 수정(weather 수정) 2025-08-21 09:32:05 +09:00
mind-one003 cc4e3ea0cf 빌드 에러 수정 2025-08-20 18:11:59 +09:00
mind-one003 1fa1a880e9 에러 수정 2025-08-20 18:01:06 +09:00
mind-one003 035f2fd4c1 rdii 산식 및 주석 추가 2025-08-20 16:58:21 +09:00
mind-one003 fda8750f14 rdii 개선 2025-08-20 16:52:19 +09:00
mind-one003 4e7d291ad9 강우영향일 공통화 진행 2025-08-20 11:15:47 +09:00
mind-one003 03f87c2042 강우량 현황 팝업수정진행중 2025-08-20 10:53:30 +09:00
264 changed files with 11390 additions and 5665 deletions
+3 -1
View File
@@ -5,4 +5,6 @@ NEXT_PUBLIC_SITE_ID=CS
NEXT_PUBLIC_SUB_DOMAIN=http://localhost:13000
NEXT_PUBLIC_SERVER_API_URL=http://dev.onasys.co.kr:8000
NEXT_PUBLIC_LINK_BACKEND_API_HOST=http://rsone.iptime.org:10014
NEXT_PUBLIC_TINY_API_KEY=t9nc4z6inquvvd5pq1vea8wcp7lb01qmqseh6egms9vpaju2
NEXT_PUBLIC_TINY_API_KEY=t9nc4z6inquvvd5pq1vea8wcp7lb01qmqseh6egms9vpaju2
NEXT_PUBLIC_SERVER_API_URL2=http://con.mind-one.co.kr:11083/
+103
View File
@@ -11,6 +11,18 @@ import {
const serverApiUrl =
process.env.NEXT_PUBLIC_SERVER_API_URL ?? "http://localhost:3000";
const serverApiUrl2 =
process.env.NEXT_PUBLIC_SERVER_API_URL2 ?? serverApiUrl;
const serverApiUrl3 =
process.env.NEXT_PUBLIC_SERVER_API_URL3 ?? serverApiUrl;
const serverApiUrl4 =
process.env.NEXT_PUBLIC_SERVER_API_URL4 ?? serverApiUrl;
const serverApiUrl5 =
process.env.NEXT_PUBLIC_SERVER_API_URL5 ?? serverApiUrl;
export function middleware(req: NextRequest) {
const pathname = req.nextUrl.pathname;
const searchParams = req.nextUrl.searchParams;
@@ -52,6 +64,97 @@ export function middleware(req: NextRequest) {
});
}
if (pathname.startsWith("/sewerage-service")) {
const requestHeaders = new Headers(req.headers);
const token = req.cookies.get(CLAIM_NAME)?.value;
const userId = req.cookies.get(AUTH_USER_ID)?.value;
const newUrl = `${serverApiUrl2}${pathname}`;
if (token) requestHeaders.set(CLAIM_NAME, token);
if (userId) requestHeaders.set(AUTH_USER_ID, userId);
logMessages.push(` Rewritten URL: ${newUrl}`);
logMessages.push("\n--------------------------------\n");
console.log(logMessages.join("\n"));
return NextResponse.rewrite(new URL(newUrl), {
headers: requestHeaders,
});
}
if (pathname.startsWith("/reuse-service")) {
const requestHeaders = new Headers(req.headers);
const token = req.cookies.get(CLAIM_NAME)?.value;
const userId = req.cookies.get(AUTH_USER_ID)?.value;
const newUrl = `${serverApiUrl3}${pathname}`;
if (token) requestHeaders.set(CLAIM_NAME, token);
if (userId) requestHeaders.set(AUTH_USER_ID, userId);
logMessages.push(` Rewritten URL: ${newUrl}`);
logMessages.push("\n--------------------------------\n");
console.log(logMessages.join("\n"));
return NextResponse.rewrite(new URL(newUrl), {
headers: requestHeaders,
});
}
if (pathname.startsWith("/operation-service")) {
const requestHeaders = new Headers(req.headers);
const token = req.cookies.get(CLAIM_NAME)?.value;
const userId = req.cookies.get(AUTH_USER_ID)?.value;
const newUrl = `${serverApiUrl4}${pathname}`;
if (token) requestHeaders.set(CLAIM_NAME, token);
if (userId) requestHeaders.set(AUTH_USER_ID, userId);
logMessages.push(` Rewritten URL: ${newUrl}`);
logMessages.push("\n--------------------------------\n");
console.log(logMessages.join("\n"));
return NextResponse.rewrite(new URL(newUrl), {
headers: requestHeaders,
});
}
if (pathname.startsWith("/ic-service")) {
const requestHeaders = new Headers(req.headers);
const token = req.cookies.get(CLAIM_NAME)?.value;
const userId = req.cookies.get(AUTH_USER_ID)?.value;
const newUrl = `${serverApiUrl5}${pathname}`;
if (token) requestHeaders.set(CLAIM_NAME, token);
if (userId) requestHeaders.set(AUTH_USER_ID, userId);
logMessages.push(` Rewritten URL: ${newUrl}`);
logMessages.push("\n--------------------------------\n");
console.log(logMessages.join("\n"));
return NextResponse.rewrite(new URL(newUrl), {
headers: requestHeaders,
});
}
if (pathname.startsWith("/dc-service")) {
const requestHeaders = new Headers(req.headers);
const token = req.cookies.get(CLAIM_NAME)?.value;
const userId = req.cookies.get(AUTH_USER_ID)?.value;
const newUrl = `${serverApiUrl5}${pathname}`;
if (token) requestHeaders.set(CLAIM_NAME, token);
if (userId) requestHeaders.set(AUTH_USER_ID, userId);
logMessages.push(` Rewritten URL: ${newUrl}`);
logMessages.push("\n--------------------------------\n");
console.log(logMessages.join("\n"));
return NextResponse.rewrite(new URL(newUrl), {
headers: requestHeaders,
});
}
if (pathname.startsWith("/user-service")) {
const queryParams = searchParams.toString();
const newUrl = `${serverApiUrl}${pathname}${
+63
View File
@@ -0,0 +1,63 @@
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 538 755">
<defs>
<style>
.cls-1 {
fill: #fff;
}
</style>
</defs>
<!-- Generator: Adobe Illustrator 28.7.9, SVG Export Plug-In . SVG Version: 1.2.0 Build 218) -->
<g>
<g id="Layer_1">
<g id="han" data-label-shift="dx,dy">
<path class="cls-1" d="M159.2,197l-5,5.8,5.1,3.7,13.2,9.7-7.3,3.5-8.2-1.2-9.4,1.4,1.4,4.9-3.5,7.3,3.8,2.6-.9,4.7,8.9-2.3,4.2-3.7,5.2,4.2-6.1,2.3.9,12,3,7-.9,3.3-.5,1.6,5.4,6.8,5.2,13.4h-3.6c0-.1,6.4,3.8,6.4,3.8l4.8,6h1.2l3.6-5.4,3.6-.6,13.8,5.9,19.7-1.1,4.6-6.5,3-5.2,8.2-1.7,11.7-17.8,7.1,1.9,4.9,10,13.2,9.6,3.8,13-1.4,12.2-.5,9.5,1.6,1.1-.6,1.3v1.1c.1,0-2.2,2.4-2.2,2.4l-17.5,7.4,7.6,19.2,16.3,1.1,8.4,10.8,12.6.6,4.2-5.2-4.6-7.9-9.2-6.2,12.1-7.1,6.4,5.2,1.3-5.6-6.6-6.5,17.5-5.8,4.8,4.4,4.8-2.1-4.7-6.5,4.5-8.8,6.3-.4,4.7-3,8,3,24.1,4.5,11.5-7.8-2.8-6.4,6.5-11.7,10.5-5.5,7.6-7.9,10.2-2.3,13.4,4.6,4.4-8,12.4,8.2,3.4-3.1.2-15.2.4-11.3,13.4-3.2,4.6-.4-1.9,9.9,9.8,4.6,1.6,12.8,12.2,9.2,9.8-8.4,15-8.9-3.7-19-21.8-40.6-5.7-10.6,1.2-6.8-4.9-6.1-4-4.9,1.2-5.2-26.3-33.1-5.8-12.1-7.1-14.9-11.9-20.9-2.9-9.4-2.1-6.7-1.8-5.2-8.7-25.5-8.6-14.4-.9-11-5.2-11-3-6.3-6,6.5-5.2,22.8-9.8,11-5.5,2.8-7.4,3.7-17.1.5-12.7-1.6-8.2,2.3-5.2-3.4-3.4-2.2-18.8-2.3-21.8,4.5-19-3.7-3.5,4.7-11.2-7.3-5.2,4.2-6.1-.7-11.5,3.5-14.1,10.8-3.7,10.1-12.9,9.8-4,7.3-8.5,6.8-2.3,1.9-9.1,4.5-4,18.3-9.2,11.5-14.3,1.2-2.1,30,5.6,1.4,3.3,9.2-1.4,2.7.9,2.6,2.9-.7,1.8,3.2-4.5,2.2,1.7,8.6,3.8,6.9,8.9,3.4Z"/>
</g>
<g id="yeongsan" data-label-shift="dx,dy">
<path class="cls-1" d="M57.4,578.4s.2,1.4.2,2.3.7,1.6.7,1.9.5,1.4.7,2.3c.2.9,1.2,1.2,1.2,1.2h0s.5,1.4.5,1.4c0,0-.5.7-.9,1.4-.5.7,1.6.9,1.6.9l2.8-.7s1.4-.7,1.4-1.2,0,0-.2-.7c-.2-.7-.5-.7-.9-1.2-.5-.5.5-.2.5-.2l.5.2,2.6-.5s.9-.5,1.4-.7c.5-.2-.2-.5-.2-.9s-.2-1.2-.2-1.2l.2-.9v-1.2c0-.5.7-.7.9-1.2.2-.5.5-.7.9-1.2.5-.5,0-.7,0-1.6s-.5-.5-.5-.9-.5,0-.5,0l-.9.5-.9.7s-.2.9-.5,1.2c-.2.2-1.4.2-1.4.2,0,0-.2-.5-1.2-.9-.9-.5,0,0-.5,0s-1.2-.2-1.2-.2c0,0-1.2-.7-1.6-.9-.5-.2-.5-.9-.5-.9h-1.2s-1.9,1.4-2.8,1.9c-.9.5,0,1.2,0,1.2Z"/>
<path class="cls-1" d="M45.2,585.7c.2.2,0,.2.7.9.7.7.5,1.6.9,1.6s.2-.5,1.2,0c.9.5,1.4.5,1.9.7.5.2,1.6.9,1.9.9s1.4.7,1.4.9-.2.2,0,.5c.2.2,0,.5.5,1.4.5.9,1.9,2.6,1.9,2.6,0,0-.7.7.5.5,1.2-.2,1.9-.2,1.9-.9s.2-1.2.2-1.4-.2-.2-.5-1.2c-.2-.9-.7-1.6-.7-1.6,0,0,1.2-.2,0-1.2-1.2-.9-.2-1.2-1.2-.9-.9.2-1.9.2-1.9.2-.2-1.2-.2-1.9-.2-1.9l-.5-.5.7-1.4h0c.5,0,.9-.2,1.2-.2s.9-.7.9-.7c0,0,.2-.2,0-.7-.2-.5-.2-.2-.9-.7s-1.6-.7-1.6-.7l-2.1-1.2-1.4-.9c-.7-.2-2.6.9-2.6.9,0,0,.9-.5,0,.7-.9,1.2-2.3,1.9-2.3,1.9,0,0-.2.5,0,.9.2.5,0,1.2.2,1.4Z"/>
<path class="cls-1" d="M28.6,585.5s0,.7,1.2.7h2.1c.5,0,.9.7.9.7v1.9l1.2.7s1.4,0,1.9-.5c.5-.5.5-.7.5-.7l-.5-1.4,2.3-.7s.5-.5.7-1.2c.2-.7-.2-1.2,0-2.3.2-1.2,0-2.8,0-2.8,0,0,.9-1.4.9-2.1s1.9-2.6,1.9-2.8h0v-.7h-1.4c-.2,0-1.7.5-2.1.7-.5.2,0,0-.9,1.2s-.2,1.6-.2,1.6l-1.9.5-1.4.7-.9.2s-1.2-.2-2.1-.2-.5.9-.5.9c0,0-1.2,1.4-1.9,1.6-.7.2-.7.7-.7.7,0,0,.9,2.3.9,2.8v.5Z"/>
<path class="cls-1" d="M41.7,591.4c-.5.2-.7-1.2-.5,0,.2,1.2,1.2,2.1,1.2,2.1l1.4.9s.9-.2,1.4,0c.5.2.9,0,.9,0l1.9.7v.2s.7-.2.5-1.6c-.2-1.4,0-1.4,0-1.4l-.7-.9-2.6-1.4h0s-2.8-.7-3-.5c-.2.2-.5-.2-.5.2s.5,1.4,0,1.6Z"/>
<path class="cls-1" d="M34.2,597.7s0,0,0,0c0,0,0,0,0,0Z"/>
<path class="cls-1" d="M45,598.9l-.7-.7-.5-.9s.2-1.4-.2-1.4-1.9-.5-1.9-.5l-1.4-.7h0s-1.4,0-1.4,0c0,0-.9,0-1.2.7-.2.7-.9.5-.9.9s-2.1,1.2-2.5,1.4c0,0,.2.2.4.5.5.7.5,1.4,1.2,1.4s2.1.2,2.3,0c.2-.2.9-.7,1.2-.5.2.2.5.5.5.9s-.5,1.2-.5,1.6.5,0,0,.5c-.5.5.2,1.4.5,1.6.2.2-.7,2.1-.7,2.1,0,0-.5.5-.5.7s1.4.7,1.6,0c.2-.7.7-1.2.9-1.4.2-.2.9-.5.9-.5,0,0-.5.2.7.2s2.1.2,2.1-.5v-1.9s-.2-1.2,0-1.4c.2-.2,0-2.3,0-2.3Z"/>
<path class="cls-1" d="M18.5,619.7c.7,0,1.9-.9,2.3,0,.5.9,1.9,2.6,1.9,2.6,0,0,.2-.2,1.4,0,1.2.2,1.2.5,2.1,0,.9-.5,1.4-1.4,1.4-1.4l1.2-1.2,3.3-1.4s-.2-.7-.7-2.1c-.5-1.4-.7-2.1-.7-2.1,0,0,1.2.2.5-.9-.7-1.2-.9-1.9-.9-1.9l-.5-1.6h0s-.7-.9-.7-.9l-2.1.2s-.2,1.2,0,1.9c.2.7.2.9,0,1.4-.2.5-.7-.5-1.2,0-.5.5-2.3.2-2.3.2h-1.2l-.9,1.4-1.2.9-2.3.9-2.1,1.4s-.5,0,0,.9c.5.9,2.1,1.6,2.8,1.6Z"/>
<path class="cls-1" d="M33.1,624h-.9l-1.4-.7-2.1.7s-.9,1.2-.9,1.6.7,1.9,1.4,2.3c.7.5,1.6.7,1.9,1.6.2.9.2,1.9.2,1.9,0,0,1.9.7,2.3-.7.5-1.4.2-2.3.7-2.6.5-.2,1.9-1.6,1.9-1.6,0,0-.5-.5.7-.5s1.6-.5,1.6-.7v-1.9l-.9-.9h.9l.7-.9s.2-.7,0-1.2c-.2-.5-.5-1.9-.5-1.9l-2.6.5h0l-1.4,1.4-.5.9s.2.9,0,1.2c-.2.2-1.2,1.4-1.2,1.4Z"/>
<path class="cls-1" d="M65.6,620.2l1.9-.7-2.1-2.6-3.5-1.9h0s-3.3.7-3.3.7l1.6,2.1.9,1.4s-.5.5-.9.9c-.5.5-1.6.7-1.6.7,0,0-.5.5-.5.9s-.9,0-2.1.7c-1.2.7-4.5,1.9-4.5,1.9h-.9c.9,0,1.6,2.6,2.3,2.6h3.1s-.2-.5.9-.7c1.2-.2,2.6-1.2,2.6-1.2,1.4.2,2.3-.7,3,.5.7,1.2,1.4.9,1.6,1.4.2.5,1.2,2.1,1.2,2.1l-.7,2.6s1.2.9,1.6.7c.5-.2,1.9-1.4,1.9-1.4l.9-1.9s-.5-1.4,0-1.9c.5-.5-1.6-1.4-1.6-1.4l-2.8-.7-1.9-2.6v-1.2l2.8-1.2Z"/>
<path class="cls-1" d="M64.2,635.5v-1.6s-3.3,1.4-3.3,1.6.9,1.6.9,1.6h1.6l.7-1.6Z"/>
<path class="cls-1" d="M59.8,639.2c0,1.2.5,2.8,1.2,3,.7.2,1.6,0,1.6,0v-3l-1.6-.9s-1.2-.2-1.2.9Z"/>
<path class="cls-1" d="M38.4,638.3c1.2,0,2.8-4.5,2.8-4.5v-1.4h0s-3.5,0-3.5,0l-2.1,1.4-3.5.7s-.2,1.9,1.4,1.9.7-.1.6-.2c0,0,.3,0,.6.2,1.6.5,3.3.7,3.3,1.2s-.7.7.5.7Z"/>
<path class="cls-1" d="M15.4,630.1h0s0,0,0,0h0Z"/>
<path class="cls-1" d="M7,642.7c.2-.5,1.2-.7,1.2-1.4s-1.6-2.6-.5-3.1c1.2-.5,2.6-.9,2.8-1.2.2-.2,1.2-.7,1.6-.5s.9.9.9.9l1.4-.5.5-.9s.2-.9.5-1.4c.2-.5.7-1.9.7-1.9v-1.2l-.7-1.6c-.3.2-2.6,2.1-2.8,2.3-.2.2-3,1.2-3.3,1.2s-3.1.2-3.1.2l-3.8.5-2.6,1.9,1.9,2.1s-.2,1.9,0,2.1c.2.2-.5,1.2.5,1.6.9.5,1.6.9,1.6.9,0,0,2.8.2,3-.2Z"/>
<path class="cls-1" d="M16.6,649.1c0-.7-1.2-1.6-1.2-1.6l-.7-.7-.9-.9s-.2-1.2-.2-1.4-.7-.9-.7-.9c0,0-2.3.2-2.3.5s-.7.7-.7.7c0,0-.2.7-1.6.7s-2.8-.5-2.6,0c.2.5-.2.9-.2,1.6s-.5,1.9-.5,1.9v1.2s.2,1.2.7,1.4c.5.2,1.2.5,1.4.7.2.2,1.4.9,1.2,1.4-.2.5,2.3.2,2.3.2l.5-.5c.2-.2,1.9-1.2,1.9-1.2,0,0,0-.9.5-.9s3.3-.5,3.3-.5v-1.6Z"/>
<polygon class="cls-1" points="12.9 643.4 12.9 643.4 12.9 643.4 12.9 643.4"/>
<path class="cls-1" d="M27.7,639.9c.5.5,1.4,1.6,2.1,1.9.7.2,1.2.5,1.4,1.2.2.7.2,1.4.5,2.1.2.7,1.9.7,1.9,1.2s.5-.2,1.4,0c.9.2.2-.2,1.6,1.2,1.4,1.4,2.3,2.1,2.6,2.6.2.5.9,0,.9,0l1.2-.9s-.2-1.6,0-1.6.2-2.1.2-2.3-.5-2.3-.5-2.3c0,0-1.2-1.4-1.4-1.4s-2.1-.7-2.1-.7l-1.2-1.2-.9-1.2-1.4-.5h0l-3.7-.7h-2.1l-1.2,1.6s.2.7.7,1.2Z"/>
<path class="cls-1" d="M32.6,663.4c.5.2,2.3.5,2.8.5s1.6-.2,1.9-.5c.2-.2.9-.2,1.6-.2s3.5.2,3.5.2c0,0,.5-.7.2-1.4-.2-.7-.9-1.4-.9-1.4l-.2-.7-.7-.5.7-1.2v-.9s-.7-.5-1.4-.5-1.4.2-1.4-.2-.9-1.9-.9-1.9l-1.4.7h0c-.9.5-1.9.7-2.1.9-.2.2-3.3.2-3.1.7.2.5.7,1.2.9,1.4.2.2.9,1.6.9,1.6,0,0-.5,1.6-.5,1.9s-.5,1.2,0,1.4Z"/>
<path class="cls-1" d="M21.3,670.4c0-.2,0-1.4.5-1.6.5-.2.7-.5.7-.7s-.7-1.2-.7-1.4-1.2-1.2-1.2-1.2l-.5-1.2-.2-1.2-.2-1.9h0s-.9-1.9-1.2-1.9-1.4-.2-1.4,0-.5.9-.5.9v.7c0,.2-.2.7,0,1.2.2.5-.2,1.4,0,1.6.2.2.2.7.5,1.4.2.7.7,1.2.7,1.4s-.2,1.2-.2,1.2c0,0-.5-.7-.5.5s-1.9,1.9-.5,2.1c1.4.2,2.8.5,3,.5s1.6-.2,1.6-.5Z"/>
<path class="cls-1" d="M27.4,673s-.5-.9,0-1.6c.3-.5.5-.9.7-1.2.2-.5.9-.5.9-.9s.5-2.3,0-2.8c-.5-.5-.9-1.6-1.4-2.3-.5-.7-.2-.9-1.2-1.6-.9-.7-1.9-1.2-1.9-1.2l-1.2.2h0s-.7,2.1-.7,2.3.2,2.3.7,2.6c.5.2,1.6,1.4,1.9,1.9.2.5.2,1.2.2,1.6s-.7,2.1-.9,2.1,0,0-1.2.5c-1.2.5-2.6.2-3,.9-.5.7-1.2,1.4-1.2,1.4v1.4c0,.2-.2.7.5.7s2.3-.2,2.8-.5c.5-.2,1.4-.7,1.4-.7l2.3-2.1,1.2-.7Z"/>
<path class="cls-1" d="M63.7,683.1c-.2-.5-1.4-2.1-1.4-2.1l-.5-.9s0-1.6-.9-1.9c-.9-.2-3-.2-3-.2l-1.6-2.3s-1.4-2.6-1.6-2.6-1.4,0-2.1-.2c-.7-.2-2.6-1.2-2.6-1.2l-.9.7c.2.7,1.6,2.8,1.6,2.8l1.2,2.3-.5,1.9s-1.9.5-2.3.5h-3s-.5-.7-.7.7c-.2,1.4-2.6,2.6-2.6,2.6h-3s-.9,1.6-.9,2.1-6.1,3.1-6.1,3.1l-1.9,2.6-1.9.5s-.5.7-.5.9-1.2,1.6-1.2,1.6h-.7s-2.3.5-2.3.9.5,1.6.5,2.1v1.6s0,1.6.2,1.6,1.4.7,1.4.7l.7,1.2s.5.2.5.5.7,1.2.7,1.2l1.2,1.2s-.5,1.6,0,2.1c.5.5.9.5,1.4.7.5.2,4.2.7,4.2.7,0,0,1.9.2,2.1.5.2.2,1.4.5,2.1,0,.7-.5,7-1.6,7-1.6,0,0-.7-.9,0-1.2.7-.2,1.9-.5,3-1.4,1.2-.9,3.7-1.2,3.7-1.2,0,0-.5-1.2.2-1.6.7-.5,2.6-2.1,2.8-2.1s2.1,1.4,2.1,1.4c0,0-.7.7.5.7s1.4-.5,1.9-2.1c.5-1.6,1.9-2.3,1.9-2.3l.5-.7s-.5-.5,0-1.6c.5-1.2.9-2.6.9-2.6v-3.5s-.5,0,.5-.5c.9-.5,2.1-2.3,1.4-3.1-.7-.7-1.6-1.9-1.9-2.3Z"/>
<polygon class="cls-1" points="49 672.3 49 672.3 49 672.3 49 672.3"/>
<path class="cls-1" d="M93.5,737.5c-2.3-1.2-4.2-2.3-4.2-2.3h-1.9l-1.2,3.5s1.4,0,1.2.9c-.2.9-1.6.5-1.2,1.6.5,1.2-.5.7,1.6,1.6,2.1.9,2.8,1.9,3.7.9.9-.9,1.9-2.6,1.9-2.6h0l.7-1.2s1.6-1.4-.7-2.6Z"/>
<path class="cls-1" d="M86.2,745l-2.8-1.9s-2.8,2.6-2.8,3.1-2.1,3.3-1.6,4,1.2,1.6,2.8,1.6,3.3-1.6,5.4-2.6c2.1-.9,2.8-2.3,3.7-1.9.9.5,2.1-.5,2.1-.5h0l-1.9-1.2-4.9-.7Z"/>
<path class="cls-1" d="M101.7,742h0l-3.5,1.2s-.9,1.2-.9,1.6.5,2.6.5,2.6c0,0-.5.5-.5,1.6v2.3s1.2,3.1,2.1,3.5c.9.5,2.6-.5,3.1-1.9.5-1.4-.9-5.6-.9-5.6,0,0-2.8-1.2-2.1-1.4.7-.2,2.8-.5,3.1-.5s.9-.7.9-.7l-.7-2.8h-.9Z"/>
<path class="cls-1" d="M115.1,720.4l-1.2-1.6-.5-1.6h0v-2.6l-2.1-3.3s-1.6-1.2-1.9-1.6c-.2-.5-3-2.3-3-2.1s-2.3,2.3-2.3,2.6-3.7,2.8-3.7,2.8c0,0,1.2,4,1.2,4.2s-1.9.2-.5,1.9c1.4,1.6,5.9,2.1,5.9,2.1,0,0,.2-1.4.5.5.2,1.9-.5,2.8-.5,3.1s1.2,1.2,2.6,1.2,3.3-.2,3.5,0c.2.2,3.5.5,3.5.5,0,0,.2,0,0-2.1-.2-2.1-1.4-3.8-1.4-3.8Z"/>
<path class="cls-1" d="M125.6,711.9c.5,0,1.4-1.9,1.4-1.9,0,0-.5-.7.9-.5,1.4.2.9,0,1.6.5.7.5,1.2.5,1.4.5s1.2-.7.5-1.4c-.7-.7-1.4-.9-1.9-1.6-.5-.7-.5-2.6-.5-2.6,0,0-.5-1.4-.7-1.4h-2.8l-.9.9h0c-.7,0-3.5-.7-3.5-.7l-.5,2.8-2.1,1.4s-.9.5-.5,1.2c.5.7.9,1.2.7,1.6-.2.5-1.6,0-1.4.7.2.7,1.6,1.9,1.6,1.9,0,0-.7,1.2-.7,1.6s.9,1.4,1.4,1.4,1.9-2.1,1.9-2.1c0,0,.5-.9.9-1.2.5-.2,2.1-1.2,2.1-1.2h.9Z"/>
<path class="cls-1" d="M141.5,712.4c0-.2-.9-.5-1.2-.7-.2-.2-1.6-.7-1.6-.7l-3-.9h-1.7s-.7,2.1-.7,2.3-.5,1.2,0,1.4c.5.2,2.1.7,2.1.7v1.2c0,.5-.7.7.5,1.2,1.2.5,4.2-.5,4.2-.5h2.6s.9-1.4.5-1.9c-.5-.5-1.6-1.9-1.6-2.1Z"/>
<path class="cls-1" d="M128.6,725.1s.2-.2.5,0c.2.2,1.4-.5,1.4-.5,0,0-.2-.5.5-.5s1.9.5,1.9.5c0,0,.7-.2.9-.7.2-.5-.2-.9,0-1.4.2-.5,0-1.6,0-1.6l-.7-1.6s-.9-.2-1.4-.2-1.2-.2-1.2-.2l-.5-.2-.9-.7h0s-2.3-.2-2.6.5c-.2.7-.7,1.6-.9,1.9-.2.2-1.9.9-1.9.9l1.4,1.4s.2.7,1.2,1.2c.9.5,2.3,1.4,2.3,1.4Z"/>
<path class="cls-1" d="M121.1,719.9c-.3-.3-.7-.5-1.2-.5h0c-.6,0-1.1.6-1.2,1.2,0,.4.2.8.5,1.2.1.2.3.5.7.7.5.3,1.4.6,1.6.2.2-.2,0-.5-.2-1.6,0-.7,0-.9-.2-1.2Z"/>
<path class="cls-1" d="M137.3,747.6c-.9-.5-1.9-.9-1.9-.9l-.5-1.2.9-1.2.2-2.3-4.2-.5-2.1.5h0s-1.2,2.1-1.4,2.6c-.2.5-2.1,1.9-2.1,2.1s0,.7-.2,1.4c-.2.7-.9,1.9,0,2.3.9.5,2.1.7,2.1.7,0,0,2.6-1.4,2.8-.7.2.7.2,1.2,1.2,1.9.9.7,2.1.9,2.3.9s.2-1.2.9-1.4c.7-.2,2.6-1.9,2.6-1.9,0,0,.2-1.9-.7-2.3Z"/>
<path class="cls-1" d="M267.1,679.6s.5-.5,0-1.6c-.5-1.2-.7-2.1-.7-2.1l-.7-1.2-.5-1.4s-.5-.5-.2-1.2c.2-.7,0-2.6,0-2.6l-.2-.7.7-.9h0c.2-.2.5-2.1.5-2.1l-3.3-2.3s-1.4.9-1.2,1.9c.2.9.9,2.1.9,2.6s.2,1.6,0,2.1c-.2.5-.9,1.2-.9,1.4s-.7,1.4-.9,1.9c-.2.5-2.8,1.9-2.8,1.9,0,0-1.9,1.9-1.9,2.1s-1.2.2-.7,1.6c.5,1.4.5,3.3.5,3.3,0,0-1.2.9-.5,1.6.7.7,1.4,1.6,2.8,2.1,1.4.5,4.2,1.6,4.2,1.6l3.1.5s2.3-.9,1.9-1.4c-.5-.5-1.6-1.4-1.6-1.4l-.5-1.2s0-1.2.5-1.9,1.6-2.6,1.6-2.6Z"/>
<polygon class="cls-1" points="279.4 600.4 279.4 586.1 272 579.9 262.7 571.1 261.3 561.5 254.5 559.9 251.7 557.3 244.7 562.9 243.5 566.9 235.1 563.3 234.4 553 235.1 535.7 240.9 533.6 245.9 532.1 247.1 523.8 256.9 510.3 248.3 507 239.9 515.4 232.7 509.4 238.7 493.8 231.6 486.6 229.2 475.8 217.2 472.2 206.4 484.2 205.2 493.8 195.7 486.6 186.1 495 186.1 502.2 176.5 510.6 159.8 515.4 157.4 523.8 140.6 521.4 127.4 517.8 124.5 512.7 119.4 508.3 115.3 512.5 110.2 512.4 96.4 517.8 89.3 530 84.4 535 85.6 538.3 88.3 540.1 87.2 541.1 82.3 539.9 76.8 551.3 72.3 553.6 67.3 564.8 76.6 566.5 73.6 571.4 75.3 574.4 80.6 583.9 85.4 585.9 85.4 589.7 80 596 78.4 589.4 69.9 588.5 68.8 590 71.3 593.4 75.4 595.9 74.3 598.4 69.7 600 68.7 603.3 63 605.4 61.9 611.5 67.8 615.5 70.4 613.1 73.2 605.9 74.3 613.6 75.3 626.5 69.7 634.5 69.7 639.2 68.1 643.4 67.8 644.3 80.4 650.4 92.7 661.4 89.3 661.9 86.5 659.8 85.6 664 79 654.2 69.4 650 67.8 656.3 70.6 661.9 74.3 663.3 77.1 670.4 72.7 669.9 66.1 661.5 62.9 648.1 58.5 642.1 51.9 654.2 55.1 668.3 59.6 674.6 61.9 673.9 65.8 676.6 67.1 680.5 69.9 680.2 72.7 677.9 79 686.6 77.7 698.2 82.8 699.7 79.7 706.7 76.6 709.9 77.4 712.1 82.5 712.8 82.7 721.2 93.1 719.9 97.3 713.3 97.1 709.8 112.1 701.6 110.7 695.9 117.2 694.3 120.8 688.2 120.2 673.4 122.8 671.1 124.7 675.1 124.5 684.5 122.4 694.3 125.7 699.9 130.4 702.1 134.8 704.2 136.9 700.4 143.5 702.3 145.8 697.6 149.1 698.3 148.3 688.6 152.1 687 152.9 684.2 151.7 682 155 673 162 671.1 167.4 666.2 174.9 662.4 179.6 664 183.8 662.6 187.1 655.8 192.4 654.7 194.6 657.2 202.1 657.2 202.7 663.8 200.6 669.2 196 669.8 194.8 663.8 189.6 664 187.5 671.6 189.1 675.6 185.9 681.9 181.9 681.2 183.1 676 181.4 674.3 176 692.2 189.2 694.5 191.7 701.4 195.5 706.3 203.9 704.4 207.4 697.8 213.3 694.1 214.2 689.9 209.3 687.1 210 684 218 684.7 221 686.6 224.2 683.9 222.7 674.6 209.2 661.4 209.5 657 212.8 653.7 210.5 650.9 215.4 646.2 211.9 643.7 213.5 642.5 216.5 642.5 222 642.5 227.6 640.4 228.1 635.9 230.9 638 231.2 641.7 231.8 647.4 236.2 650.7 238.4 657 234.6 663.8 232.6 672.3 234.9 676.9 238.7 676.9 243.5 679.8 244.5 675.1 243.3 671.1 245.9 662.9 249.9 659.4 255 664.1 261.6 661 262.3 655.8 265.1 651.9 267 645.5 264.6 642 261.1 642.5 257.9 642 248 646 246.3 642 239.9 634.6 244.2 626.8 246.3 631 251.6 632.8 262.5 623.5 278.8 628.6 285.4 617.2 285.4 607.6 279.4 600.4"/>
</g>
<g id="nakdong" data-label-shift="dx,dy">
<path class="cls-1" d="M405.4,649.3l-2.1-.2-1.6,1.2-.9,1.6-1.2.2-.9-.5v-1.2l.2-.9,1.4-.9.9-.7v-.9l.9-.9.7-1.2-.2-1.6-.2-1.4.5-3v-1.9l-1.6-1.6-.9-.9.2-1.9.7-2.8h0c0,0,1.6-.5,1.6-.5,0,0,1.2-.9,1.2-1.2s.2-.7.2-.7l-.2-.9-1.4-.9-1.9-.7-1.6.2-1.2.5-.9,1.2-.7,1.2-.2,1.2.5,1.9v.9l-.5.7-.7.2-1.2.2-.9.5-.5.5-.2,1.2-.2.5h-1.4l-1.4.5s-.9.2-1.2.2-.7.7-.7.7l-1.2.5h-1.4c-.2,0-.7.2-.7.2l-.5.5v.5l.2.7s.7.7.9.7,0,.7,0,.7l.2.9v.7l.2.9.5.5.7.5s.5.5.7.5.2.7.2.7c0,0,.5.7.5.9v2.1h-.2s-.7-.2-.9-.2-.5-.5-.5-.5l-.9-.7h-.9l-.9-.5-.5-.7-.7-1.2-.7-.5-.5-.2-.5.2-.7.7-.7.2h-.9l-1.4-.9-1.4-.9-1.4-.7h-1.2l-.5.2-.7.9-.5.7-1.2.7s-.2,0-.5.2c-.2.2-.7.5-.7.5l-.5.7-.7,1.2-.5,1.2-.9.9v3.3l1.2,1.4s.7,1.4.7,1.6.2,1.4.2,1.4l.7,1.2.7,1.6,1.6.2,1.4-.9.7-1.2.7-.7h2.6l1.4-1.2.9-1.6.7-.9.7-.5.5.5.5.7v2.6s.5.5.7.5,0,.7,0,.7l-.7,1.2-1.2,1.9-.5.7-.2.5-.2.5-.9.5-1.2.2-1.4.2-.7.5-.5.5-.2.7,1.4.5.5.5v.7l.5.5.7.2h1.2l2.1.2.7.5.2.7-.2.5-.7.5s-.9.7-1.2.7-.5.9-.5.9l-.2.7.2.9v.7l.9.2.9.7,1.2.2v.9l-.2.2-.9.5-1.4.5-.7.2-.5.7v.9l.5.7s.5.5.7.5,1.4.2,1.4.2c0,0,1.4.2,1.6.2s.9-.5.9-.5l1.2-.5,1.2-.7.5-.7v-.7l.2-1.2s.5-.9.5-1.2.9-.5.9-.5l1.4-.2.2-.7-.9-.9-.7-1.4.5-1.6v-1.2l.7-.7,1.6-.2,1.6-.2.7-.9.2-1.2v-2.1l.7-.7,1.9.2,1.6-.2.5,2.1,1.2,1.4,2.1.9,1.6-.7.2-1.2-.2-1.2-1.6-1.2-.7-1.4.2-1.2-1.2-.7-.9-.9.5-1.4h1.9c.2,0,.7-.5.7-.5l.7-.9v-1.6h.9c.2,0,.7-.5.7-.5l.2-1.4s.2-.5.7-.7c.5-.2,0-1.4,0-1.4v-1.4Z"/>
<path class="cls-1" d="M330.3,650.8v-1.2l-.9-.5h0s-4.2-1.2-4.2-.9-2.8,0-2.8,0l-1.4.9s-.2.7-.2.9.2,1.2.2,1.2l.5.2.9.7,2.8.5h1.9l.9-.7.9-.7.9-.2.5-.2Z"/>
<polygon class="cls-1" points="333.8 654.8 332.6 654.1 332.2 652.9 331.7 652.7 331 652.9 329.8 653.9 329.6 654.8 329.1 656 329.1 657.6 329.4 659 329.8 659.7 330.8 659.7 331.9 659.5 332.4 659 333.8 659 335 658.8 335.2 657.8 335.2 656.9 334.7 655.7 333.8 654.8"/>
<polygon class="cls-1" points="308 649.2 307.6 648.4 307.6 647.5 308 646.3 308.7 645.2 308.7 644.2 308.3 644 307.3 643.5 306.4 642.8 305.5 641.9 304.7 641.2 303.1 641.4 302.2 642.8 302.2 644.7 301.2 645.2 300.8 644.2 300.5 642.6 301 641.4 301.7 639.8 302.4 638.4 303.6 637.2 303.6 636.5 303.3 635.8 302.6 635.8 301 636 299.8 637 298.4 638.1 298.2 639.5 297.3 640 295.6 640.9 294.7 642.4 293.5 643.5 293.3 644.9 293.3 645.9 293.5 647 294.2 648.2 295.4 648.4 297 649.2 299.4 649.2 301.2 648.7 303.1 649.2 304.1 649.9 306.2 651 307.8 652 308.3 651.7 309.4 651.7 309.7 651 309.2 650.3 308 649.2"/>
<path class="cls-1" d="M305.2,653.4l-1.2-.5-.9-.7-.7-.2h-2.1l-1.6-.2-.9-.7h-1.6l-1.2,1.2-1.6,1.2-.9.7v.7l-1.4-.2-.5-1.2-.9-1.4-.2-.7-.5-.9-1.2-.5-1.2-.5-.5-.5s-.2-.5-.2-.7-.2-1.2-.2-1.2v-.5c0-.2-.7-.7-.7-.7l-.2-.7-.5-1.2-.2-1.4.7-.9.2-.9,1.6-.2.7-.5.5-.2.2-.7.2-1.2.5-.5.7-.9v-.7l-.2-1.2-.5-1.4.2-1.4-2.1-1.4h-3.1l-1.9.2-1.4,1.2-.9,1.4-.5,1.2-.5,1.4v.7l-1.6.5-.9.5-.7.9s.2.5,0,.7c-.2.2-1.2.9-1.2.9v1.4l-.5,1.2-.7.5-.9.5-.2.9v1.4l.2,1.2-.2,1.4.5,1.6.5,1.9,1.2,1.9h0v1.6l.2,1.4.7.9.9.7.2.7-.2.7-.9.9-.9.7-.5.7-.2.7,1.2.7.7.5,1.4.7v.7l.2,1.2.5.9.9.5.9-.2h1.9l1.2-.2.9-.5.9-.9v-1.4l-.5-.9-.2-1.4.2-.7.7-.5,1.9-.2,1.2-.9h2.3l.5.9v.7s-.5.7-.5.9-.2,1.2-.2,1.2l-.5,1.4v.5l-.2.9.2.5.2.5.2,1.2v1.2l.5.9,2.1.2,2.3.7,1.6-.2,1.2.2.9-.7s.5.5.7.5.5.9.5.9l1.6.7,1.6.2h.7l.2-1.2-.2-1.4-.7-.7-.2-.9v-1.2l.5-.5.9-.9.7-.2.5-.5v-2.3s-.5-2.1-.5-2.3v-.9l.2-1.2.5-1.4s-.2-.9,0-.9.7-.7.7-.7l.7-.5.2-.9-.2-.9-1.2-.5Z"/>
<polygon class="cls-1" points="533.7 451.9 529.9 457.3 516.8 465.7 509.4 457.5 516.6 447.7 513.8 417.3 513.1 408.8 521.3 392.4 522.9 355.1 523.6 353.3 531.1 333.9 526.2 315.4 526.2 282.1 519.8 263.8 504.8 272.7 495 281.2 482.8 272 481.1 259.2 471.4 254.5 473.3 244.6 468.7 245 455.3 248.2 454.9 259.5 454.7 274.8 451.4 277.9 438.9 269.7 434.5 277.6 421.1 273 410.9 275.3 403.3 283.3 392.8 288.8 386.2 300.5 389 306.9 377.6 314.7 353.5 310.3 345.4 307.2 340.7 310.3 334.5 310.7 330 319.5 334.6 326 329.8 328.1 325 323.7 307.5 329.5 314.2 336 312.9 341.5 306.5 336.4 294.4 343.5 303.6 349.6 308.1 357.5 304 362.7 314.1 371.6 316.5 383.6 314.1 388.4 326.1 392 323.3 402.6 325.2 414.4 315.5 413.8 315 423.6 307.5 439.1 298 443 298.5 447.6 301.2 454.4 296.8 462.5 286.2 472.3 276.7 473.4 269.4 480.7 267.1 483.1 264.5 485.8 256.9 505.2 256.9 510.3 247.1 523.8 245.9 532.1 240.9 533.6 235.1 535.7 234.4 553 235.1 563.3 243.5 566.9 244.7 562.9 251.7 557.3 254.5 559.9 261.3 561.5 262.7 571.1 272 579.9 279.4 586.1 279.4 600.4 285.4 607.6 285.4 617.2 278.8 628.6 282.6 628.4 288.8 622.6 289.3 620.3 291.9 621.5 292.3 624.3 296.3 623 298.7 624.3 301.6 622.6 298.9 615.9 301.2 614.9 303.4 615.5 304.7 611.2 309.9 609.7 307.1 614.2 306.9 625.2 305.5 632.3 314.8 637.2 317 641.5 318.3 642.1 322.4 640.3 325.1 641.7 326.8 641.4 329.4 634.9 335.5 635.5 338.5 640.5 342.8 638.4 346.2 633 347.4 636.3 348.6 639.8 343.1 642.3 344.4 645.9 349.4 647.4 351.4 645.9 353.5 647.7 353.3 655.5 347.7 654.1 346.2 655.7 351 659.7 353.7 666.6 356.3 667.8 358.7 665.9 359.9 659.7 358.5 655.6 361.6 654.2 365.6 646.5 363.1 643.5 360.7 647.8 358.5 646.8 361.3 632.3 361.1 630.7 361 629.5 368.3 628 371.4 624.3 365.9 619.1 357.2 620.8 355.4 623.6 351.9 624.1 354.8 618.5 361.5 616.3 367.3 614.4 366.1 610.6 379 609.8 381.7 611.6 383.5 619.4 389.9 616.8 383.5 596.4 387.2 591.5 388.9 592.4 387.7 599.2 390.1 604.4 394.7 605 398 608.8 399.5 604.8 401.5 606.5 400.5 612.2 406.2 614.7 414 613.3 414.9 615.6 420.1 616.2 424.6 617.3 428.8 614.1 432.5 616.6 438.5 610.1 436.6 622.3 438 626.7 441.3 625.8 442.5 620.6 445.7 622.8 453.5 612.9 457 616.4 461.6 616.6 461.7 613.8 459.8 610.5 463.1 606.6 469.9 608.2 480.9 594.4 480.7 591.3 485.5 581.8 491 579.8 494.6 576.1 498.5 573.7 497.1 571.8 499.6 567.6 499.9 561.3 498 558.2 504.1 554 504 546.1 505.5 548.8 506.9 554.5 511.6 551.2 514.6 544.4 514.4 537.4 515.8 532.7 513.9 528 514 525.4 524.7 493.4 527.1 486.2 527.8 477.8 535.1 466.5 538 455.6 533.7 451.9"/>
</g>
<g id="geum" data-label-shift="dx,dy">
<path class="cls-1" d="M298,443l9.5-3.9,7.5-15.6.5-9.8,9.7.6-1.9-11.8,2.8-10.6-12-3.6,2.4-4.8-2.4-12-10.1-8.9-12.6-.6-8.4-10.8-16.3-1.1-7.6-19.2,17.5-7.4,2.3-2.4v-1.1c-.1,0,.4-1.3.4-1.3l-1.6-1.1.5-9.5,1.4-12.2-3.8-13-13.2-9.6-4.9-10-7.1-1.9-11.7,17.8-8.2,1.7-3,5.2-4.6,6.5-19.7,1.1-13.8-5.9-3.6.6-3.6,5.4h-1.2l-4.8-6-6.4-3.9-5-.2-9.1-18.5-5.4,3-2.4-5.7-11.4-2.8-11.7-9.2h-3.9c0,.1-3.4,4.8-3.4,4.8l1,6.2,2.1,5.4-1.2.8-4.4-7.5-6.7-3.2-6.3-.3-5.2,3.3,5.9,3.4-3.6,2.2,5.3,4.4,2.5.8.4,3-6.5,6.1-8.7,11.2-4-1.9,6.4-13.5-1.6-1.9,1.1-7.9-2.1-3-4.7,14.5-3,1.8-3.8-5.7-4.4,2.7.5,8.4-1.5,1.7-3.3-.8-4.2,3.2-5.1,13.8.5,1.5,3.9-.2.2-6.5,5.6,2.5,2.8,5.3-7.4,2.4v3c0,0,5.9,1.2,5.9,1.2l4.3-1.5,2.1-3.3,4-.3-1.4,6,4.1,3.7-2.4,9.4,4.3,6.1,1.1,27,11.6,2.1-6.6-26.7,2.3-4.1-6.3-4.9,1.7-1.9,1-6.9,2-1.5,2.2,9,4.4,3.2,3.1-1.9,3.1-6.1,1.8,1.5-1.9,8.6,2,14.4,1.9,13.7-2.8,6.5,8.2,7.8v2.1l-6.9,2.9,2.9,21.8-1.6,1.9-5.9,6.7,1.3,2.7,3.3-2.7,8.2,2.8,6.2,7.7-1.2,2.8,5.1,13.1,5.6,3.1-19.1.5-1.8,3.3,6.4,3.1-.6,10.7,7.3,2.8,3-3.3,8.9,1.9,9.4-3.4.3,1.4.2.9-3.1,5.4-5.1-.9-9.4,3.5,6.8,6.4,4.3,1.4-.2,5.6-20.6-5.8-6.4,13.7-18.1,10.4-1.9,6.6,5.9,4.7h19.9s3.8,4.2,3.8,4.2l-.5,3.4,3,5.1,13.2,3.6,16.8,2.4,2.4-8.4,16.8-4.8,9.6-8.4v-7.2l9.6-8.4,9.6,7.2,1.2-9.6,10.8-12,12,3.6,2.4,10.8,7.2,7.2-6,15.6,7.2,6,8.4-8.4,8.6,3.3v-5.1s7.6-19.4,7.6-19.4l12.2-12.4,9.6-1.1,10.5-9.8,4.5-8.1-2.7-6.8-.6-4.6Z"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 KiB

+1
View File
@@ -0,0 +1 @@
export { BoardApi } from "../api/board-service";
@@ -0,0 +1,60 @@
import { client } from "@/shared/api";
import { ENDPOINT } from "@/shared/config";
import type {
Board,
BoardFormData,
BoardList,
BoardParams,
BoardPopupList,
BoardPopupParams,
BoardService,
} from "../model/board-interface";
export class BoardApiService implements BoardService {
public async getBoardList(params?: BoardParams): Promise<BoardList> {
const response = await client.get<BoardList>(
`${ENDPOINT.BOARD_SERVICE.BBS}`,
{ params },
);
return response.data;
}
public async getBoardPopupList(
params: BoardPopupParams,
): Promise<BoardPopupList> {
const response = await client.get<BoardPopupList>(
`${ENDPOINT.BOARD_SERVICE.BBS}`,
{ params },
);
return response.data;
}
public async getBoardInfo(bbsId: string): Promise<Board> {
const response = await client.get<Board>(
`${ENDPOINT.BOARD_SERVICE.BBS}/${bbsId}`,
);
return response.data;
}
public async createBoard(data: BoardFormData): Promise<Board> {
const response = await client.post<Board>(
`${ENDPOINT.BOARD_SERVICE.BBS}`,
data,
);
return response.data;
}
public async updateBoard(bbsId: string, data: BoardFormData): Promise<Board> {
const response = await client.put<Board>(
`${ENDPOINT.BOARD_SERVICE.BBS}/${bbsId}`,
data,
);
return response.data;
}
public async deleteBoard(bbsId: string): Promise<void> {
await client.delete(`${ENDPOINT.BOARD_SERVICE.BBS}/${bbsId}`);
}
}
export const BoardApi = new BoardApiService();
@@ -0,0 +1,17 @@
import { client } from "@/shared/api";
import { ENDPOINT } from "@/shared/config";
import type {
BoardTemplate,
BoardTemplateService,
} from "../model/board-template-interface";
export class BoardTemplateApiService implements BoardTemplateService {
public async getBoardTemplate(bbsTypeCd: string): Promise<BoardTemplate> {
const response = await client.get<BoardTemplate>(
`${ENDPOINT.BOARD_SERVICE.BBS_TEMPLATES}/${bbsTypeCd}`,
);
return response.data;
}
}
export const BoardTemplateApi = new BoardTemplateApiService();
+11
View File
@@ -0,0 +1,11 @@
export { BoardApi } from "./api/board-service";
export {
boardFormSchema,
BOARD_POSTING_CODE,
type Board,
type BoardFormData,
type BoardParams,
type BoardPopup,
type BoardPostingCode,
} from "./model/board-interface";
export { BoardTemplateApi } from "./api/board-template-service";
@@ -0,0 +1,99 @@
import { z } from "zod";
import type { PageableList, PageableParams } from "@/shared/model";
import type { BbsType } from "@/shared/store";
export const BOARD_POSTING_CODE = {
팝업게시: "01",
상단게시: "02",
기간게시: "03",
} as const;
export type BoardPostingCode =
(typeof BOARD_POSTING_CODE)[keyof typeof BOARD_POSTING_CODE];
export interface BoardParams extends PageableParams {
keywordType?: string;
keyword?: string;
bbsId?: number;
bbsTypeCd?: string;
bbsNm?: string;
bbsExpln?: string;
rfrncUseYn?: string;
atflUseYn?: string;
atflMaxCnt?: number;
atflMaxFileSz?: number;
ansUseYn?: string;
cmntUseYn?: string;
dgstfnEvlUseYn?: string;
smsUseYn?: string;
upndFixUseYn?: string;
pstgPrdUseYn?: string;
popupUseYn?: string;
delYn?: string;
}
export interface BoardPopupParams extends PageableParams {
bbsNm?: string;
}
export interface Board {
bbsId: number;
bbsTypeCd: BbsType;
bbsTypeNm: string;
bbsNm: string;
bbsExpln: string;
rfrncUseYn: string;
atflUseYn: string;
atflMaxCnt: number;
atflMaxFileSz: number;
ansUseYn: string;
ansUseAuthrt: string;
cmntUseYn: string;
dgstfnEvlUseYn: string;
smsUseYn: string;
upndFixUseYn: string;
pstgPrdUseYn: string;
popupUseYn: string;
delYn: string;
useYn: string;
prvcIndctYn: string;
mdfcnDt: string;
mdfrNm: string;
}
export interface BoardPopup extends Board {
pstCnt: number;
}
export const boardFormSchema = z.object({
bbsTypeCd: z.string(),
bbsNm: z.string(),
bbsExpln: z.string(),
rfrncUseYn: z.string(),
atflUseYn: z.string(),
atflMaxCnt: z.number().nullish(),
atflMaxFileSz: z.number().nullish(),
ansUseYn: z.string(),
ansUseAuthrt: z.string().nullish(),
cmntUseYn: z.string(),
dgstfnEvlUseYn: z.string(),
smsUseYn: z.string(),
upndFixUseYn: z.string(),
pstgPrdUseYn: z.string(),
popupUseYn: z.string(),
useYn: z.string(),
prvcIndctYn: z.string(),
});
export type BoardList = PageableList<Board>;
export type BoardPopupList = PageableList<BoardPopup>;
export type BoardFormData = z.infer<typeof boardFormSchema>;
export interface BoardService {
getBoardList: (params: BoardParams) => Promise<BoardList>;
getBoardPopupList: (params: BoardPopupParams) => Promise<BoardPopupList>;
getBoardInfo: (bbsId: string) => Promise<Board>;
createBoard: (data: BoardFormData) => Promise<Board>;
updateBoard: (bbsId: string, data: BoardFormData) => Promise<Board>;
deleteBoard: (bbsId: string) => Promise<void>;
}
@@ -0,0 +1,24 @@
export interface BoardTemplate {
bbsTypeCd: string;
rfrncUseYn: string;
atflUseYn: string;
atflMaxCnt: number;
atflMaxFileSz: number;
ansUseYn: string;
cmntUseYn: string;
dgstfnEvlUseYn: string;
smsUseYn: string;
upndFixUseYn: string;
pstgPrdUseYn: string;
popupUseYn: string;
regDt: string;
rgtr: string;
mdfcnDt: string;
mdfr: string;
rgtrNm: string;
mdfrNm: string;
}
export interface BoardTemplateService {
getBoardTemplate: (bbsTypeCd: string) => Promise<BoardTemplate>;
}
@@ -0,0 +1,97 @@
import { client } from "@/shared/api";
import { ENDPOINT } from "@/shared/config";
import {
postFormSchema,
postUpdateFormSchema,
type Post,
type MovePost,
type DeletePost,
type PostInfo,
type PostList,
type MyPostList,
type PostParams,
type MyPostParams,
type PostFormData,
type PostUpdateFormData,
type PostService,
} from "../model/post-interface";
export class PostApiService implements PostService {
public async getPostList(
bbsId: number,
params: PostParams,
): Promise<PostList> {
const response = await client.get<PostList>(
`${ENDPOINT.BOARD_SERVICE.POSTS}/${bbsId}`,
{ params },
);
return response.data;
}
public async getMyPostList(
params?: MyPostParams,
): Promise<MyPostList> {
const response = await client.get<MyPostList>(
`${ENDPOINT.BOARD_SERVICE.POSTS}/mypost`,
{ params },
);
return response.data;
}
public async getPostInfo(bbsId: number, pstNo: number): Promise<PostInfo> {
const response = await client.get<PostInfo>(
`${ENDPOINT.BOARD_SERVICE.POSTS}/${bbsId}/${pstNo}`,
);
return response.data;
}
public async createPost(data: PostFormData): Promise<Post> {
const validatedData = postFormSchema.parse(data);
const response = await client.post<Post>(
`${ENDPOINT.BOARD_SERVICE.POSTS}`,
validatedData,
);
return response.data;
}
public async updatePost(
bbsId: number,
pstNo: number,
data: PostUpdateFormData,
): Promise<Post> {
const validatedData = postUpdateFormSchema.parse(data);
const response = await client.put<Post>(
`${ENDPOINT.BOARD_SERVICE.POSTS}/${bbsId}/${pstNo}`,
validatedData,
);
return response.data;
}
public async deletePost(
bbsId: number,
pstNo: number,
delRsn?: string,
): Promise<void> {
await client.delete(`${ENDPOINT.BOARD_SERVICE.POSTS}/${bbsId}/${pstNo}`, {
params: { delRsn },
});
}
public async softDeletePost(data: DeletePost[]): Promise<void> {
await client.post(`${ENDPOINT.BOARD_SERVICE.POSTS}/softDeleteSels`, data);
}
public async hardDeletePost(data: DeletePost[]): Promise<void> {
await client.post(`${ENDPOINT.BOARD_SERVICE.POSTS}/hardDeleteSels`, data);
}
public async movePost(data: MovePost[]): Promise<void> {
await client.post(`${ENDPOINT.BOARD_SERVICE.POSTS}/movePstByBbsId`, data);
}
public async restorePost(data: DeletePost[]): Promise<void> {
await client.post(`${ENDPOINT.BOARD_SERVICE.POSTS}/restoreSels`, data);
}
}
export const PostApi = new PostApiService();
+17
View File
@@ -0,0 +1,17 @@
export { PostApi } from "./api/post-service";
export {
postFormSchema,
postUpdateFormSchema,
type Post,
type MyPost,
type MovePost,
type DeletePost,
type PostList,
type PostParams,
type MyPostParams,
type PostFormData,
type PostUpdateFormData,
type PostService,
} from "./model/post-interface";
export { deleteReasonMessages } from "./model/delete-reason-messages";
export { PostPageGuard } from "./lib/post-page-guard";
@@ -0,0 +1,39 @@
import { useEffect } from "react";
import { useQuery } from "@tanstack/react-query";
import { usePathname, useRouter } from "next/navigation";
import { BoardApi } from "@/entities/board/@x/post";
import { useAlertStore, useMenuStore } from "@/shared/lib";
function PostPageGuard({
bbsId,
children,
}: {
bbsId: string;
children: React.ReactNode;
}) {
const router = useRouter();
const pathname = usePathname();
const alert = useAlertStore((state) => state.setMessage);
const setBbsInfo = useMenuStore((state) => state.setBbsInfo);
const { data: boardInfo, isLoading } = useQuery({
queryKey: [bbsId],
queryFn: () => BoardApi.getBoardInfo(bbsId),
});
useEffect(() => {
if (!boardInfo) return;
setBbsInfo(boardInfo);
}, [boardInfo]);
if (!isLoading && pathname && boardInfo) {
if (!pathname.includes(boardInfo.bbsTypeCd.toLowerCase())) {
alert("잘못된 경로로 접속하였습니다.", router.back);
return null;
}
}
return children;
}
export { PostPageGuard };
@@ -0,0 +1,11 @@
export const deleteReasonMessages = {
"저작권 침해":
"타인의 저작물을 허락 없이 게시하는 경우 저작권 침해로 간주되어 삭제될 수 있습니다.",
명예훼손: "타인의 명예를 훼손하는 내용의 게시물은 삭제될 수 있습니다.",
"개인정보 노출": "타인의 개인정보를 노출하는 게시물도 삭제될 수 있습니다.",
"불법 정보 유통":
"불법적인 상품이나 서비스를 판매하거나 홍보하는 게시물은 삭제될 수 있습니다.",
"욕설 및 비방":
"심한 욕설이나 비방, 모욕적인 내용이 포함된 게시물은 삭제될 수 있습니다.",
"광고성 정보": "지나치게 광고성이 짙은 게시물은 삭제될 수 있습니다.",
};
@@ -0,0 +1,119 @@
import { z } from "zod";
import type { PageableList, PageableParams } from "@/shared/model";
export interface PostParams extends PageableParams {
keywordType?: string;
keyword?: string;
popupYn?: string;
upndFixYn?: string;
prdPstgYn?: string;
siteId?: string;
bbsTypeCd?: string;
ansUseYn?: string;
}
export interface MyPostParams extends PageableParams {
keywordType?: string;
keyword?: string;
bbsId?: number | null;
delYn?: string;
frDateYmd?: string;
toDateYmd?: string;
}
export interface Post {
rowNo: number;
bbsId: number;
pstNo: number;
pstTtl: string;
pstCn: string;
inqNocs: number;
rfrncUrl: string;
popupYn: string;
upndFixYn: string;
prdPstgYn: string;
rootPath: string;
pstPath: string;
ansPstn: number;
wrtrNm: string;
wrtrCplc: string;
atflCd: string;
regDt: string;
rgtrNm: string;
cmntCnt: number;
}
export interface MyPost extends Post {
bbsNm: string;
bbsTypeCd: string;
}
export interface PostInfo extends Post {
pstCn: string;
rgtr: string;
mdfcnDt: string;
mdfr: string;
}
export interface MovePost {
fromBbsId: number;
toBbsId?: number;
pstNo: number;
}
export interface DeletePost {
bbsId: number;
pstNo: number;
delRsn?: string;
}
const postEtcSchema = z.object({
bbsPstgTypeCd: z.string(),
pstgPrdSeCd: z.string(),
pstgBgngDt: z.string().nullish(),
pstgEndDt: z.string().nullish(),
});
export const postFormSchema = z.object({
bbsId: z.number(),
pstTtl: z.string().nonempty(),
pstCn: z.string().nullish(),
rfrncUrl: z.string().nullish(),
popupYn: z.string().nullish(),
popupYnEtc: z.array(postEtcSchema).nullish(),
upndFixYn: z.string().nullish(),
upndFixYnEtc: z.array(postEtcSchema).nullish(),
prdPstgYn: z.string().nullish(),
prdPstgYnEtc: z.array(postEtcSchema).nullish(),
pstPswd: z.string(),
wrtrNm: z.string().nullish(),
wrtrCplc: z.string().nullish(),
atflCd: z.string().nullish(),
parentPstNo: z.number().nullish(),
});
export const postUpdateFormSchema = postFormSchema.omit({
bbsId: true,
parentPstNo: true,
});
export type PostList = PageableList<Post>;
export type MyPostList = PageableList<MyPost>;
export type PostFormData = z.infer<typeof postFormSchema>;
export type PostUpdateFormData = z.infer<typeof postUpdateFormSchema>;
export interface PostService {
getPostList(bbsId: number, params: PostParams): Promise<PostList>;
getMyPostList(params: MyPostParams): Promise<MyPostList>;
getPostInfo(bbsId: number, pstNo: number): Promise<PostInfo>;
createPost(data: PostFormData): Promise<Post>;
updatePost(
bbsId: number,
pstNo: number,
data: PostUpdateFormData,
): Promise<Post>;
deletePost(bbsId: number, pstNo: number, delRsn?: string): Promise<void>;
softDeletePost(data: DeletePost[]): Promise<void>;
hardDeletePost(data: DeletePost[]): Promise<void>;
movePost(data: MovePost[]): Promise<void>;
}
@@ -0,0 +1,14 @@
import { client } from "@/shared/api";
import { ENDPOINT } from "@/shared/config";
import type { Dashboard, DashboardService } from "../model/dashboard-interface";
export class DashboardApiService implements DashboardService {
public async getDashboard(): Promise<Dashboard> {
const response = await client.get<Dashboard>(
ENDPOINT.CMS_SERVICE.DASHBOARD,
);
return response.data;
}
}
export const DashboardApi = new DashboardApiService();
@@ -0,0 +1,212 @@
#mapArea {
display: flex;
align-items: center;
justify-content: center;
}
.stage {
--map-inset: 7.5%;
aspect-ratio: 0.72/1;
width: 100%;
max-height: 100%;
position: relative;
margin: auto;
}
.bgLayer {
position: absolute;
inset: var(--map-inset);
display: flex;
align-items: center;
justify-content: center;
z-index: 1;
width: calc(100% - var(--map-inset) * 2);
height: calc(100% - var(--map-inset) * 2);
background-image: url("/images/region_map_bg.png");
background-repeat: no-repeat;
background-size: contain;
background-position: center center;
image-rendering: -webkit-optimize-contrast;
image-rendering: crisp-edges;
image-rendering: pixelated;
opacity: 0.7;
filter: drop-shadow(0 1px 0 rgba(0, 0, 0, 0.02));
pointer-events: none;
min-height: 200px;
}
.svgLayer {
position: absolute;
inset: var(--map-inset);
display: flex;
align-items: center;
justify-content: center;
z-index: 2;
width: calc(100% - var(--map-inset) * 2);
height: calc(100% - var(--map-inset) * 2);
}
.svgLayer > svg {
max-width: 100%;
max-height: 100%;
width: auto;
height: auto;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
image-rendering: -webkit-optimize-contrast;
image-rendering: crisp-edges;
shape-rendering: geometricPrecision;
}
/* SVG 스타일을 위한 컨테이너 */
.svgContainer :global(svg) :global(path) {
fill: rgba(0, 150, 255, 0.2) !important;
stroke: #0066cc;
stroke-width: 1;
vector-effect: non-scaling-stroke;
}
.svgContainer :global(svg) :global(.cls-1) {
fill: rgba(0, 150, 255, 0.2) !important;
stroke: #0066cc;
stroke-width: 1;
vector-effect: non-scaling-stroke;
}
.svgContainer :global(svg) :global(.basin) {
opacity: 0;
pointer-events: all;
transition: opacity 0.15s ease;
cursor: pointer;
}
.svgContainer :global(svg) :global(.basin.active),
.svgContainer :global(svg) :global(.basin:hover) {
opacity: 1;
}
.svgContainer :global(svg) :global(.basin) :global(path),
.svgContainer :global(svg) :global(.basin) :global(polygon),
.svgContainer :global(svg) :global(.basin) :global(polyline) {
fill: rgba(0, 209, 209, 0.5);
stroke: #399AC3;
stroke-width: 1.3;
vector-effect: non-scaling-stroke;
}
/* 팝업 + 배지 */
.popup {
position: absolute;
width: 300px;
height: 150px;
min-width: 220px;
background: #fff;
border: 1px solid #e5e7eb;
border-radius: 10px;
box-shadow:
0 12px 24px rgba(0, 0, 0, 0.18),
0 2px 0 rgba(0, 0, 0, 0.05);
opacity: 0;
visibility: hidden;
transform: translate(-50%, -8px) scale(0.98);
transition:
opacity 0.12s,
visibility 0.12s,
transform 0.12s;
pointer-events: none;
z-index: 10;
}
.popup.show {
opacity: 1 !important;
visibility: visible !important;
transform: translate(-50%, -12px) scale(1) !important;
}
.show {
opacity: 1;
visibility: visible;
}
.popup .head {
display: grid;
grid-template-columns: 1fr 1fr;
background: #d1ecfa;
border-bottom: 1px solid #c8e4f3;
font-weight: 700;
font-size: 16px;
}
.popup .head > div {
padding: 10px 12px;
text-align: center;
}
.popup .body {
padding: 6px 10px 8px;
}
.popup td {
padding: 8px 10px;
border-bottom: 1px solid #eef2f7;
font-size: 14px;
}
.popup .arrow {
position: absolute;
left: 50%;
bottom: -8px;
transform: translateX(-50%);
width: 0;
height: 0;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-top: 10px solid #fff;
filter: drop-shadow(0 1px 0 rgba(0, 0, 0, 0.1));
}
.badge {
position: absolute;
z-index: 9;
padding: 6px 10px;
border-radius: 8px;
background: #1e40af;
color: #fff;
font-weight: 700;
transform: translate(-50%, -50%);
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.22);
pointer-events: none;
opacity: 0;
visibility: hidden;
transition: opacity 0.12s, visibility 0.12s;
}
.badge.show {
opacity: 1;
visibility: visible;
}
/* 권역 라벨 */
.labelsLayer {
position: absolute;
inset: var(--map-inset);
pointer-events: none;
z-index: 3;
width: 100%;
height: 100%;
}
.basinLabel {
position: absolute;
transform: translate(-50%, -50%);
pointer-events: none;
padding: 6px 12px;
border-radius: 6px;
font-weight: 700;
font-size: 16px;
background: #ffffffee;
border: 2px solid #d0d0d0;
white-space: nowrap;
min-width: 60px;
text-align: center;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
.basinLabel.active {
background: #006bf8;
color: #fff;
border-color: #96c3ff;
box-shadow: 0 4px 12px rgba(0, 107, 248, 0.3);
}
@@ -0,0 +1,425 @@
import React, { useEffect, useRef } from "react";
import styles from "./KoreaBasinMap.module.css"; // 추가
const SVG_URL = "/images/region_map.svg"; // public 폴더에 region_map.svg 위치 필요
const MANUAL_LABEL_POS = {
han: { x: 0.52, y: 0.14 },
geum: { x: 0.28, y: 0.47 },
nakdong: { x: 0.64, y: 0.47 },
yeongsan: { x: 0.18, y: 0.77 },
};
const BASIN_DATA = {
han: {
name: "한강",
colTitle: "시설수",
rows: [
["500m³ 미만", 100000000],
["500m³ 이상", 100000000],
],
},
geum: {
name: "금강",
colTitle: "시설수",
rows: [
["500m³ 미만", 100000000],
["500m³ 이상", 100000000],
],
},
nakdong: {
name: "낙동강",
colTitle: "시설수",
rows: [
["500m³ 미만", 100000000],
["500m³ 이상", 100000000],
],
},
yeongsan: {
name: "영산강",
colTitle: "시설수",
rows: [
["500m³ 미만", 100000000],
["500m³ 이상", 100000000],
],
},
};
const BASIN_IDS = [
{ key: "han", labels: ["한강", "han"] },
{ key: "geum", labels: ["금강", "geum"] },
{ key: "nakdong", labels: ["낙동강", "nakdong"] },
{ key: "yeongsan", labels: ["영산강", "yeongsan"] },
];
function fmt(n: number) {
return new Intl.NumberFormat("ko-KR").format(n);
}
export function KoreaBasinMap() {
const stageRef = useRef<HTMLDivElement>(null);
const svgLayerRef = useRef<HTMLDivElement>(null);
const labelsLayerRef = useRef<HTMLDivElement>(null);
const popupRef = useRef<HTMLDivElement>(null);
const badgeRef = useRef<HTMLDivElement>(null);
const rowsRef = useRef<HTMLTableSectionElement>(null);
const colTitleRef = useRef<HTMLTableCellElement>(null);
useEffect(() => {
let svg: SVGSVGElement | null = null;
let gs: SVGGElement[] = [];
let labels: HTMLDivElement[] = [];
console.log("Loading SVG from:", SVG_URL);
fetch(SVG_URL)
.then((r) => {
console.log("SVG fetch response:", r.status, r.statusText);
if (!r.ok) throw new Error(`HTTP error! status: ${r.status}`);
return r.text();
})
.then((txt) => {
console.log("SVG content loaded, length:", txt.length);
if (!svgLayerRef.current) {
console.error("svgLayerRef.current is null");
return;
}
svgLayerRef.current.innerHTML = txt;
svg = svgLayerRef.current.querySelector("svg");
if (!svg) {
console.error("SVG element not found in loaded content");
return;
}
console.log("SVG element found:", svg);
// viewBox/크기 세팅
if (!svg.hasAttribute("viewBox")) {
const bb = svg.getBBox();
svg.setAttribute(
"viewBox",
[bb.x, bb.y, bb.width, bb.height].join(" "),
);
}
const vb = (svg.getAttribute("viewBox") || "").split(/\s+/).map(Number);
if (vb.length === 4 && vb[3]! > 0 && stageRef.current) {
stageRef.current!.style.aspectRatio = String(vb[2]! / vb[3]!);
}
svg!.setAttribute("preserveAspectRatio", "xMidYMid meet");
svg.style.width = "100%";
svg.style.height = "100%";
// 1) 지도 그룹 수집
gs = [];
console.log("Looking for basin groups in SVG...");
BASIN_IDS.forEach((item) => {
let g: SVGGElement | null = null;
for (const id of item.labels) {
g = svg!.getElementById(id) as SVGGElement | null;
if (g) {
console.log(`Found group for ${item.key} with id '${id}':`, g);
break;
}
}
if (!g) {
console.warn(`No group found for ${item.key} with labels:`, item.labels);
return;
}
g.classList.add("basin");
(g as SVGGElement & { dataset: { key: string; label: string } }).dataset.key = item.key;
(g as SVGGElement & { dataset: { key: string; label: string } }).dataset.label = item.labels[0] || '';
// 패스에 기본 스타일 적용
const paths = g.querySelectorAll('path');
paths.forEach((path) => {
path.style.fill = 'rgba(0, 150, 255, 0.2)';
path.style.stroke = '#0066cc';
path.style.strokeWidth = '1';
path.style.vectorEffect = 'non-scaling-stroke';
});
gs.push(g);
});
console.log(`Found ${gs.length} basin groups`);
// 각 유역 그룹의 패스 정보 확인
gs.forEach((g, index) => {
const paths = g.querySelectorAll('path');
console.log(`Group ${index} (${(g as SVGGElement & { dataset: { key: string } }).dataset.key}):`, {
element: g,
pathCount: paths.length,
paths: Array.from(paths).map(p => ({
className: p.className.baseVal,
d: p.getAttribute('d')?.substring(0, 50) + '...'
}))
});
});
// 2) 함수들 먼저 정의
const clear = () => {
gs.forEach((el) => el.classList.remove("active"));
if (popupRef.current) {
if (styles.show) {
popupRef.current.classList.remove(styles.show);
}
popupRef.current.style.opacity = "0";
popupRef.current.style.visibility = "hidden";
}
if (badgeRef.current) {
if (styles.show) {
badgeRef.current.classList.remove(styles.show);
}
badgeRef.current.style.opacity = "0";
badgeRef.current.style.visibility = "hidden";
}
labels.forEach((l) => l.classList.remove("active"));
};
function showFor(g: SVGGElement) {
console.log("showFor called for:", g);
const key = (g as SVGGElement & { dataset: { key: string; label: string } }).dataset.key;
const data = (BASIN_DATA as Record<string, { name: string; colTitle: string; rows: (string | number)[][] }>)[key] || {
name: (g as SVGGElement & { dataset: { label: string } }).dataset.label,
colTitle: "",
rows: [],
};
console.log("Data for popup:", data);
if (badgeRef.current) badgeRef.current.textContent = data.name;
if (colTitleRef.current)
colTitleRef.current.textContent = data.colTitle || "???";
if (rowsRef.current)
rowsRef.current.innerHTML = data.rows
.map(
(r: (string | number)[]) =>
`<tr><td>${r[0]}</td><td style="text-align:right">${fmt(Number(r[1]) || 0)}</td></tr>`,
)
.join("");
if (!stageRef.current) return;
const sRect = stageRef.current.getBoundingClientRect(),
r = g.getBoundingClientRect();
const cx = (r.left + r.right) / 2 - sRect.left;
const ty = r.top - sRect.top;
console.log("Popup position:", { cx, ty });
if (badgeRef.current) {
badgeRef.current.style.left = cx + "px";
badgeRef.current.style.top = ty + 24 + "px";
}
if (popupRef.current) {
popupRef.current.style.left = cx + "px";
popupRef.current.style.top = ty + 6 + "px";
popupRef.current.style.opacity = "1";
popupRef.current.style.visibility = "visible";
if (styles.show) {
popupRef.current.classList.add(styles.show);
}
console.log("Added show class to popup:", popupRef.current.classList.toString());
}
if (badgeRef.current && styles.show) {
badgeRef.current.classList.add(styles.show);
}
if (popupRef.current) {
const pRect = popupRef.current.getBoundingClientRect();
const x = Math.max(
12 + pRect.width / 2,
Math.min(cx, sRect.width - 12 - pRect.width / 2),
);
popupRef.current.style.left = x + "px";
if (badgeRef.current) badgeRef.current.style.left = x + "px";
}
}
function showForWithLabel(g: SVGGElement) {
console.log("showForWithLabel called for:", g);
showFor(g);
const idx = gs.indexOf(g);
labels.forEach((l) => l.classList.remove("active"));
if (idx >= 0) labels[idx]!.classList.add("active");
}
// 3) 라벨 DOM 생성
labels = [];
if (labelsLayerRef.current) {
labelsLayerRef.current.innerHTML = "";
gs.forEach((g) => {
const el = document.createElement("div");
el.className = styles.basinLabel || '';
el.textContent = (g as SVGGElement & { dataset: { label: string } }).dataset.label || '';
labelsLayerRef.current!.appendChild(el);
labels.push(el);
});
}
// 3) 라벨 위치
function positionLabels() {
if (!stageRef.current || !svg) return;
const sRect = stageRef.current.getBoundingClientRect();
const inset =
parseFloat(
getComputedStyle(stageRef.current).getPropertyValue(
"--map-inset",
) || "0",
) / 100;
const left = sRect.width * inset,
top = sRect.height * inset;
const w = sRect.width * (1 - inset * 2),
h = sRect.height * (1 - inset * 2);
const [vx, vy, vw, vh] = (
svg!.getAttribute("viewBox") || "0 0 100 100"
)
.split(/\s+/)
.map(Number);
const svgRect = svg.getBoundingClientRect();
const stageRect = stageRef.current.getBoundingClientRect();
const offsetX = svgRect.left - stageRect.left - left;
const offsetY = svgRect.top - stageRect.top - top;
gs.forEach((g, i) => {
const key = (g as SVGGElement & { dataset: { key: string } }).dataset.key;
const manual = (MANUAL_LABEL_POS as Record<string, { x?: number; y?: number; px?: number; py?: number }>)[key];
let px, py;
if (
manual &&
(("x" in manual && "y" in manual) ||
("px" in manual && "py" in manual))
) {
if ("px" in manual) {
px = left + (manual.px || 0) + offsetX;
py = top + (manual.py || 0) + offsetY;
} else {
px = left + w * (manual.x || 0) + offsetX;
py = top + h * (manual.y || 0) + offsetY;
}
} else {
const b = g.getBBox();
const cx = b.x + b.width / 2,
cy = b.y + b.height / 2;
px = ((cx - vx!) / vw!) * w + left + offsetX;
py = ((cy - vy!) / vh!) * h + top + offsetY;
}
labels[i]!.style.left = `${px}px`;
labels[i]!.style.top = `${py + 18}px`;
});
}
// 4) 상호작용 (함수들은 이미 위에서 정의됨)
gs.forEach((g) => {
g.addEventListener("mouseenter", () => {
clear();
g.classList.add("active");
showForWithLabel(g);
});
g.addEventListener("mousemove", () => {
if (g.classList.contains("active")) showForWithLabel(g);
});
g.addEventListener("mouseleave", clear);
g.addEventListener("click", (e) => {
e.stopPropagation();
clear();
g.classList.add("active");
showForWithLabel(g);
});
});
if (stageRef.current) {
stageRef.current.addEventListener("mouseleave", clear);
stageRef.current.addEventListener("click", () => clear());
}
// 5) 실행
positionLabels();
window.addEventListener("resize", positionLabels);
new window.ResizeObserver(positionLabels).observe(stageRef.current!);
})
.catch((error) => {
console.error("Error loading SVG:", error);
if (svgLayerRef.current)
svgLayerRef.current.innerHTML =
`<div style="display: flex; align-items: center; justify-content: center; height: 100%; color: #666; font-size: 14px;">지도를 불러올 수 없습니다. (${error.message})</div>`;
});
// cleanup
return () => {
window.removeEventListener("resize", () => {});
};
}, []);
// 스타일은 필요에 따라 tailwind, css 등으로 커스터마이즈하세요.
return (
<div
ref={stageRef}
id="stage"
style={
{
width: "100%",
height: "560px",
position: "relative",
zIndex: 20,
"--map-inset": "0",
} as React.CSSProperties
}
>
<div
className={styles.bgLayer}
id="bgLayer"
/>
<div
ref={svgLayerRef}
id="svgLayer"
className={`${styles.svgLayer} ${styles.svgContainer}`}
style={{ width: "100%", height: "100%" }}
/>
<div
ref={labelsLayerRef}
id="labelsLayer"
className={styles.labelsLayer}
style={{
position: "absolute",
left: 0,
top: 0,
width: "100%",
height: "100%",
pointerEvents: "none",
}}
/>
<div
ref={badgeRef}
id="badge"
className={styles.badge}
style={{ position: "absolute", zIndex: 10, display: "block" }}
/>
<div
ref={popupRef}
id="popup"
className={styles.popup}
style={{
position: "absolute",
zIndex: 20,
background: "#fff",
border: "1px solid #ccc",
borderRadius: 8,
padding: 12,
minWidth: 160,
boxShadow: "0 2px 8px #0002",
display: "block",
opacity: 0,
visibility: "hidden",
}}
>
<table style={{ width: "100%" }}>
<thead>
<tr>
<th>구분</th>
<th ref={colTitleRef} id="colTitle">
시설수
</th>
</tr>
</thead>
<tbody ref={rowsRef} id="rows"></tbody>
</table>
</div>
</div>
);
}
@@ -0,0 +1,172 @@
import { type ChartData, type ChartOptions } from "chart.js";
const commonData = {
labels: ["1", "2", "3", "4", "5", "6", "7"],
datasets: [
{
fill: true,
pointRadius: 0,
tension: 0.5,
},
],
};
const commonOptions = {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false,
},
},
scales: {
x: {
display: false,
},
y: {
display: false,
},
},
};
export const chartData: Record<
string,
{ data: ChartData<"line" | "bar">; options: ChartOptions<"line" | "bar"> }
> = {
memberChartData: {
data: {
...commonData,
datasets: [
{
...commonData.datasets[0],
data: [8, 10, 7, 12, 9, 13, 12],
borderColor: "rgba(255, 255, 255, 0.6)",
backgroundColor: "rgba(255, 255, 255, 0.1)",
},
],
},
options: {
...commonOptions,
scales: {
...commonOptions.scales,
y: {
...commonOptions.scales.y,
min: 5,
max: 15,
},
},
},
},
postChartData: {
data: {
...commonData,
datasets: [
{
...commonData.datasets[0],
data: [5200, 5350, 5450, 5520, 5600, 5650, 5678],
borderColor: "rgba(86, 138, 255, 1)",
backgroundColor: "rgba(86, 138, 255, 0.1)",
},
],
},
options: {
...commonOptions,
},
},
visitorChartData: {
data: {
...commonData,
datasets: [
{
...commonData.datasets[0],
data: [1800, 2100, 1950, 2300, 2150, 2250, 2345],
borderColor: "rgba(149, 131, 252)",
backgroundColor: "rgba(149, 131, 252, 0.1)",
},
],
},
options: {
...commonOptions,
},
},
apiChartData: {
data: {
...commonData,
datasets: [
{
...commonData.datasets[0],
data: [41000, 42500, 43200, 44100, 44800, 45200, 45678],
borderColor: "rgba(220, 103, 206)",
backgroundColor: "rgba(220, 103, 206, 0.1)",
},
],
},
options: {
...commonOptions,
},
},
siteAccessChartData: {
data: {
labels: Array.from({ length: 24 }, (_, i) =>
i.toString().padStart(2, "0"),
),
datasets: [],
},
options: {
...commonOptions,
plugins: {
legend: {
position: "top",
},
tooltip: {
mode: "index",
intersect: false,
},
},
scales: {
x: {
title: {
text: "시간대",
},
},
y: {
title: {
text: "접속자 수",
},
beginAtZero: true,
},
},
},
},
menuAccessChartData: {
data: {
labels: [],
datasets: [],
},
options: {
...commonOptions,
plugins: {
legend: {
position: "top",
},
tooltip: {
mode: "index",
intersect: false,
},
},
scales: {
x: {
title: {
text: "메뉴명",
},
},
y: {
title: {
text: "접속 횟수",
},
beginAtZero: true,
},
},
},
},
};
@@ -0,0 +1,32 @@
export interface SiteStatisticsContent {
siteId: string;
siteNm: string;
accessHour: string;
accessCnt: number;
}
export interface MenuStatisticsContent {
menuCd: number;
menuNm: string;
accessCnt: number;
}
export interface Dashboard {
memberTotCnt: number;
memberTodayCnt: number;
pstTotCnt: number;
pstTodayCnt: number;
accessTodayCnt: number;
accessBefDayPer: number;
apiTodayCnt: number;
waitMemberCnt: number;
waitCntnCnt: number;
notiList: [];
schdlList: [];
siteAccessList: SiteStatisticsContent[];
menuAccessList: MenuStatisticsContent[];
}
export interface DashboardService {
getDashboard(): Promise<Dashboard>;
}
@@ -0,0 +1,75 @@
import dayjs from "dayjs";
import type { ColumnDef } from "@tanstack/react-table";
import { Badge } from "@common/components";
import type { Post, MyPost } from "@/entities/post";
const noticePostTableColumns: ColumnDef<Post>[] = [
{
header: "번호",
cell: ({ row, table }) => {
if (row.original.upndFixYn === "Y") {
return (
<Badge
color="orange"
className="flex size-8 items-center justify-center"
>
<i className="diveicon di-volume-up-fill" />
</Badge>
);
}
const totalRows = table.getRowCount();
const currentPage = table.getState().pagination.pageIndex;
const pageSize = table.getState().pagination.pageSize;
return totalRows - (currentPage * pageSize + row.index);
},
},
{
accessorKey: "pstTtl",
header: "제목",
},
{
accessorKey: "wrtrNm",
header: "작성자",
},
{
accessorKey: "regDt",
header: "작성일",
cell: ({ row }) => dayjs(row.original.regDt).format("YYYY-MM-DD"),
},
{
accessorKey: "inqNocs",
header: "조회수",
},
];
const myPostTableColumns: ColumnDef<MyPost>[] = [
{
header: "번호",
cell: ({ row, table }) => {
const totalRows = table.getRowCount();
const currentPage = table.getState().pagination.pageIndex;
const pageSize = table.getState().pagination.pageSize;
return totalRows - (currentPage * pageSize + row.index);
},
},
{
accessorKey: "pstTtl",
header: "제목",
},
{
accessorKey: "wrtrNm",
header: "작성자",
},
{
accessorKey: "regDt",
header: "작성일",
cell: ({ row }) => dayjs(row.original.regDt).format("YYYY-MM-DD"),
},
{
accessorKey: "inqNocs",
header: "조회수",
},
];
export { noticePostTableColumns, myPostTableColumns };
+237 -76
View File
@@ -1,9 +1,36 @@
"use client";
import { useEffect, useState } from 'react';
import { useRouter } from 'next/navigation';
import { tokenManager } from '@/entities/auth/lib/token-manager';
import { client } from '@/shared/api';
import { ENDPOINT } from '@/shared/config';
import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import { tokenManager } from "@/entities/auth/lib/token-manager";
import { client } from "@/shared/api";
import { ENDPOINT } from "@/shared/config";
import { KoreaBasinMap } from "../lib/KoreaBasinMap";
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
PointElement,
LineElement,
BarElement,
Filler,
Legend,
Tooltip,
ArcElement,
} from "chart.js";
import { Doughnut } from "react-chartjs-2";
// Chart.js 등록
ChartJS.register(
CategoryScale,
LinearScale,
PointElement,
LineElement,
BarElement,
Filler,
Legend,
Tooltip,
ArcElement
);
interface UserInfo {
email?: string;
@@ -14,124 +41,258 @@ interface UserInfo {
function DashboardPage() {
const [userInfo, setUserInfo] = useState<UserInfo | null>(null);
const [error, setError] = useState('');
const [error, setError] = useState("");
const router = useRouter();
useEffect(() => {
const fetchUserInfo = async () => {
console.log('fetchUserInfo called');
const fetchUserInfo = async () => {
console.log("fetchUserInfo called");
try {
// tokenManager를 통해 토큰 확인
const accessToken = tokenManager.getToken('Authorization');
const userId = tokenManager.getToken('token-id');
const accessToken = tokenManager.getToken("Authorization");
const userId = tokenManager.getToken("token-id");
if (!accessToken || !userId) {
console.log('No tokens found, redirecting to login');
setError('로그인이 필요합니다.');
router.push('/auth/login');
console.log("No tokens found, redirecting to login");
setError("로그인이 필요합니다.");
router.push("/auth/login");
return;
}
console.log('Fetching user info with userId:', userId);
console.log("Fetching user info with userId:", userId);
// client를 사용하여 API 호출 (자동 토큰 처리)
const response = await client.get(`${ENDPOINT.USER_SERVICE.USERS}/${userId}`);
const response = await client.get(
`${ENDPOINT.USER_SERVICE.USERS}/${userId}`,
);
if (response.data) {
console.log('User info received:', response.data);
console.log("User info received:", response.data);
setUserInfo(response.data);
} else {
setError('사용자 정보를 불러올 수 없습니다.');
setError("사용자 정보를 불러올 수 없습니다.");
}
} catch (error) {
console.error('Error fetching user info:', error);
if (error instanceof Error && error.message.includes('401')) {
setError('인증이 만료되었습니다. 다시 로그인해주세요.');
console.error("Error fetching user info:", error);
if (error instanceof Error && error.message.includes("401")) {
setError("인증이 만료되었습니다. 다시 로그인해주세요.");
tokenManager.clearAuthToken();
router.push('/auth/login');
router.push("/auth/login");
} else {
setError('네트워크 오류가 발생했습니다.');
setError("네트워크 오류가 발생했습니다.");
}
}
};
fetchUserInfo();
}, [router]);
const handleLogout = () => {
console.log('Logging out...');
console.log("Logging out...");
// localStorage 정리
localStorage.removeItem('tempToken');
localStorage.removeItem("tempToken");
// tokenManager를 통해 쿠키 정리
tokenManager.clearAuthToken();
router.push('/auth/logout');
router.push("/auth/logout");
};
const handleChangePassword = () => {
router.push('/otp?next=change-password');
const handleChangePassword = () => {
router.push("/otp?next=change-password");
};
return (
<div className="p-6">
<div className="flex flex-col gap-1">
{/* 첫번째 라인 */}
<div className="grid grid-cols-7 gap-1">
{/* 총 회원수 카드 */}
<div className="card card-border h-80 !p-0 col-span-2">
<div className="grid grid-cols-8 gap-1">
{/* 첫번쨰 열 */}
<div className="col-span-2 h-250 !p-0">
{/* 전국 하수처리시설 가동률 */}
<div className="card card-border">
<div className="card-header text-foreground">
<h3 className="text-2xl font-medium">전국 하수처리시설 가동률</h3>
</div>
<div className="h-60 p-4">
<Doughnut
data={{
datasets: [{
data: [75, 25], // 75% 가동률
backgroundColor: ['#00DFE5', '#f5f5f5'],
borderWidth: 0
}]
}}
options={{
responsive: true,
maintainAspectRatio: false,
cutout: '70%',
circumference: 180, // 반원
rotation: -90, // 왼쪽에서 시작
plugins: {
legend: {
display: false
},
tooltip: {
enabled: false
}
}
}}
plugins={[{
id: 'centerText',
afterDraw: (chart) => {
const ctx = chart.ctx;
const centerX = chart.width / 2;
const centerY = chart.height / 2;
// 가동률 텍스트
ctx.save();
ctx.font = 'bold 24px Arial';
ctx.fillStyle = '#00DFE5';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText('75%', centerX, centerY + 10);
// 라벨 텍스트
ctx.font = '12px Arial';
ctx.fillStyle = '#666';
ctx.fillText('가동률', centerX, centerY + 30);
ctx.restore();
}
}]}
/>
</div>
</div>
{/* 오수관로 및 우수관로 현황 */}
<div className="card card-border">
<div className="card-header text-foreground">
<h3 className="text-2xl font-medium">오수관로 및 우수관로 현황</h3>
</div>
<div className="h-60 p-4"></div>
</div>
{/* 하수처리수 재이용 */}
<div className="card card-border">
<div className="card-header text-foreground">
<h3 className="text-2xl font-medium">하수처리수 재이용</h3>
</div>
<div className="h-60 p-4"></div>
</div>
</div>
{/* 전체 게시물 카드 */}
<div className="card card-border h-80 !p-0 col-span-2">
{/* 두번쨰 열 */}
<div className="col-span-2 h-250 !p-0">
{/* 하수처리시설(개소) */}
<div className="card card-border">
<div className="card-header text-foreground">
<h3 className="text-2xl font-medium">하수처리시설(개소)</h3>
</div>
<div className="grid grid-cols-2 gap-1 h-60 !p-0">
<div className="card card-border">
<div className="card-header text-foreground text-center">
<h3 className="text-l font-medium" style={{textAlign: "center", width: "100%"}}>500㎥ 미만(개소)</h3>
</div>
<div style={{fontSize: "38px", textAlign: "center", fontWeight: "600", lineHeight: "1.2", color: "#0ec58a", padding: "2px 0"}}>3,567 <span style={{fontSize: "14px", color: "#000000"}}>개소</span></div>
</div>
<div className="card card-border">
<div className="card-header text-foreground text-center">
<h3 className="text-l font-medium" style={{textAlign: "center", width: "100%"}}>500㎥ 이상(개소)</h3>
</div>
<div style={{fontSize: "38px", textAlign: "center", fontWeight: "600", lineHeight: "1.2", color: "#0ec58a", padding: "2px 0"}}>767 <span style={{fontSize: "14px", color: "#000000"}}>개소</span></div>
</div>
<div className="col-span-2" style={{width: "100%", textAlign: "right"}}>기준년월 : 2025.09 </div>
</div>
</div>
{/* 노후하수관로현황 */}
<div className="card card-border">
<div className="card-header text-foreground">
<h3 className="text-2xl font-medium">노후하수관로현황</h3>
</div>
<div className="h-70 p-4">
</div>
</div>
{/* 재이용시설(개소) */}
<div className="card card-border">
<div className="card-header text-foreground">
<h3 className="text-2xl font-medium">재이용시설(개소)</h3>
</div>
<div className="h-70 p-4">
</div>
</div>
</div>
{/* 오늘 접속자 수 카드 */}
<div className="card card-border h-80 !p-0 col-span-2">
{/* 지도영역 */}
<div className="col-span-3 h-200 !p-0 relative z-10">
<div className="card card-border">
<div className="card-header text-foreground">
<h3 className="text-2xl font-medium">유역별 정보</h3>
</div>
<KoreaBasinMap />
</div>
</div>
{/* 사용자 정보 카드 */}
<div className="card card-border h-80 p-10 col-span-1">
<h2 className="text-2xl mb-6">사용자 정보</h2>
{error && <div className="text-red-500 mb-4">{error}</div>}
{userInfo ? (
<div className="mb-4">
<div><b>아이디:</b> {userInfo.userId}</div>
<div><b>이메일:</b> {userInfo.email || userInfo.userId}</div>
<div><b>이름:</b> {userInfo.userName || '-'}</div>
<div><b>2FA 활성화:</b> {userInfo.twoFactorEnabled ? '예' : '아니오'}</div>
<div className="card card-border col-span-1 h-80 p-10">
<h2 className="mb-6 text-2xl">사용자 정보</h2>
{error && <div className="mb-4 text-red-500">{error}</div>}
{userInfo ? (
<div className="mb-4">
<div>
<b>아이디:</b> {userInfo.userId}
</div>
) : (
!error && <div>사용자 정보를 불러오는 중...</div>
)}
<button className="btn w-full mb-2" onClick={handleLogout}>로그아웃</button>
<button className="btn w-full" onClick={handleChangePassword}>패스워드 변경</button>
</div>
<div>
<b>이메일:</b> {userInfo.email || userInfo.userId}
</div>
<div>
<b>이름:</b> {userInfo.userName || "-"}
</div>
<div>
<b>2FA 활성화:</b>{" "}
{userInfo.twoFactorEnabled ? "예" : "아니오"}
</div>
</div>
) : (
!error && <div>사용자 정보를 불러오는 중...</div>
)}
<button className="btn mb-2 w-full" onClick={handleLogout}>
로그아웃
</button>
<button className="btn w-full" onClick={handleChangePassword}>
패스워드 변경
</button>
</div>
</div>
{/* 두번째 라인 */}
<div className="grid grid-cols-2 gap-1">
<div className="card card-border h-80 p-10 col-span-1">
<div className="grid grid-cols-4 gap-1">
<div className="card card-border"id="grouping-statistics">
<div className="card-header text-foreground">
<h3 className="text-2xl font-medium">지원현황</h3>
</div>
<div className="h-70 p-4">
</div>
</div>
<div className="card card-border">
<div className="card-header text-foreground">
<h3 className="text-2xl font-medium">자료관 자료현황</h3>
</div>
<div className="h-70 p-4">
</div>
</div>
<div className="card card-border">
<div className="card-header text-foreground">
<h3 className="text-2xl font-medium">공지사항</h3>
</div>
<div className="h-70 p-4">
</div>
</div>
<div className="card card-border h-80 p-10 col-span-1">
</div>
</div>
{/* 배너 영역 */}
<div className="card card-border">
{/* 세번째 라인 */}
<div className="grid grid-cols-2 gap-1">
<div className="card card-border h-80 p-10 col-span-1">
</div>
<div className="card card-border h-80 p-10 col-span-1">
</div>
</div>
{/* 네번째 라인 */}
<div className="grid grid-cols-2 gap-1">
<div className="card card-border h-80 p-10 col-span-1">
</div>
<div className="card card-border h-80 p-10 col-span-1">
</div>
</div>
</div>
@@ -139,4 +300,4 @@ function DashboardPage() {
);
}
export { DashboardPage };
export { DashboardPage };
+11
View File
@@ -69,6 +69,17 @@ export const ENDPOINT = {
POSTS_COMMENTS: "/board-service/api/v1/posts-cmnts",
POST_EVALUATION: "/board-service/api/v1/pstEvl",
},
SEWERAGE_SERVICE: {
PPL_COUNTS: "/sewerage-service/api/v1/ms/pplCounts",
OLD_PPL_COUNTS: "/sewerage-service/api/v1/ms/oldPplCounts",
},
IC_SERVICE: {
GROUPING_STATISTICS: "/ic-service/api/v1/nti/grouping-statistics",
},
DC_SERVICE: {
DATA_STATUS: "/dc-service/api/v1/dc/dataStatus",
},
};
export const JWT_EXPIRATION_TIME = 1800000;
+1 -1
View File
@@ -19,4 +19,4 @@ NEXT_PUBLIC_SEWERAGE_API_URL=http://con.mind-one.co.kr:11083/sewerage-service/ap
NEXT_PUBLIC_FINDADRESS_URL=https://business.juso.go.kr/addrlink/addrLinkApi.do
NEXT_PUBLIC_WR_ADDRESS_KEY = devU01TX0FVVEgyMDI1MDgyNTEwMzkwNDExNjEwNTM=
NEXT_PRIVATE_WR_ADDRESS_KEY = devU01TX0FVVEgyMDI1MDgyNTEwMzkwNDExNjEwNTM=
+1 -1
View File
@@ -22,4 +22,4 @@ NEXT_PUBLIC_SEWERAGE_API_URL=http://con.mind-one.co.kr:11083/sewerage-service/ap
NEXT_PUBLIC_FINDADRESS_URL=https://business.juso.go.kr/addrlink/addrLinkApi.do
NEXT_PUBLIC_WR_ADDRESS_KEY = devU01TX0FVVEgyMDI1MDgyNTEwMzkwNDExNjEwNTM=
NEXT_PRIVATE_WR_ADDRESS_KEY = devU01TX0FVVEgyMDI1MDgyNTEwMzkwNDExNjEwNTM=
+7 -7
View File
@@ -1,9 +1,9 @@
NEXT_PUBLIC_SITE_ID = DM
NEXT_PUBLIC_PORT = 11035
NEXT_PUBLIC_PROXY_HOST = http://con.mind-one.co.kr:11035
NEXT_PUBLIC_SERVER_API_URL = http://apigateway.iipbs-dev.svc.cluster.local:8000/api/v1
NEXT_PUBLIC_FO_SERVER_API_URL = http://apigateway.iipbs-dev.svc.cluster.local:8000/operation-service/api/v1
NEXT_PUBLIC_CS_SERVER_API_URL = http://apigateway.iipbs-dev.svc.cluster.local:8000
NEXT_PUBLIC_PROXY_HOST = https://reuse.hasuon.or.kr
NEXT_PUBLIC_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/api/v1
NEXT_PUBLIC_FO_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/operation-service/api/v1
NEXT_PUBLIC_CS_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000
NEXT_PUBLIC_CS_TUS_UPLOAD = /attach-service/api/v1/tus/upload
NEXT_PUBLIC_GEOSERVER_URL = http://172.29.143.87:8080/geoserver
NEXT_PUBLIC_LX_GEOSERVER_URL = http://172.29.143.87:8080/geoserver_swl
@@ -11,11 +11,11 @@ NEXT_PUBLIC_CLAIM_NAME = Authorization
NEXT_PUBLIC_AUTH_USER_ID = token-id
NEXT_PUBLIC_ACCESS_TOKEN = access-token
NEXT_PUBLIC_REFRESH_TOKEN = refresh-token
NEXT_PUBLIC_REUSE_API_URL=http://con.mind-one.co.kr:11080/api/v1
NEXT_PUBLIC_REUSE_API_URL= http://apigateway.iipbs-was.svc.cluster.local:8000/reuse-service/api/v1
NEXT_PUBLIC_NGII_URL = http://10.98.25.94:18080/openapi/Gettile.do?apiKey=BDE2BEF39DAFEC293AB6730150F222AC
NEXT_PUBLIC_SEWERAGE_API_URL = http://apigateway.iipbs-dev.svc.cluster.local:8000/sewerage-service/api
NEXT_PUBLIC_SEWERAGE_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/sewerage-service/api
NEXT_PUBLIC_FINDADRESS_URL=https://business.juso.go.kr/addrlink/addrLinkApi.do
NEXT_PUBLIC_WR_ADDRESS_KEY = U01TXOFVVEgyMDI1MDgyODE0MTAxNzExNjEyMjA=
NEXT_PRIVATE_WR_ADDRESS_KEY = U01TXOFVVEgyMDI1MDgyODE0MTAxNzExNjEyMjA=
@@ -58,6 +58,7 @@ export default function MyForm() {
dataList={demandCompList}
rtnValue={callback}
rtnInputData={handleInsertSdmData}
openNetwork={true}
/>
<Toaster position="top-center" />
</div>
+92 -257
View File
@@ -1,237 +1,45 @@
'use client';
import { regionData, regionIdMap } from '@/app/common/comFunction';
import { useDmStore } from '@/app/store';
import type { DmStatusDataType } from '@/app/store/wrStatus/type';
import { CHART_FORM, MainChart, type ChartConfig } from '@common/business_components';
import React, { useEffect, useRef, useState, useMemo, useCallback } from 'react';
import React, { useEffect, useRef, useState, useCallback } from 'react';
interface RegionData {
name: string;
x: number;
y: number;
values: number[];
interface WrStatusChartProps {
chartForm: string;
chartConfig: ChartConfig;
chartData: any;
chartTitle: string;
chartClassName?: string;
graphSize?: number;
yFieldText? : string | undefined;
yFieldText2? : string | undefined;
showLegend? : boolean;
setXAxisYearTick ?: boolean;
}
interface TableData {
region: string;
sewage: string;
rainwater: string;
reclaimed: string;
thermal: string;
}
export default function WrStatusPage() {
const WrStatusPage: React.FC = () => {
const { Common, dmStatus, getDmStatusData,initializeCommonData} = useDmStore((state) => state);
const { statusData,facilityTotals ,chartData} = dmStatus;
const [selectedRegion, setSelectedRegion] = useState<string | null>(null);
const [hoveredRegion, setHoveredRegion] = useState<string | null>(null);
const [tooltipPosition, setTooltipPosition] = useState<{ x: number; y: number } | null>(null);
const [chartOption, setChartOption] = useState<WrStatusChartProps>({} as WrStatusChartProps)
const svgContainerRef = useRef<HTMLDivElement>(null);
const [chartData] = useState<any[]>([
{
label : '서울',
하수 : 4,
빗물 : 816,
중수도 : 371,
온배수 : 0
},
{
label : '부산',
하수 : 13,
빗물 : 68,
중수도 : 20,
온배수 : 1
},
{
label : '대구',
하수 : 9,
빗물 : 294,
중수도 : 14,
온배수 : 2
},
{
label : '인천',
하수 : 17,
빗물 : 165,
중수도 : 35,
온배수 : 15
},
{
label : '광주',
하수 : 3,
빗물 : 74,
중수도 : 15,
온배수 : 15
},
{
label : '대전',
하수 : 2,
빗물 : 52,
중수도 : 11,
온배수 : 20
},
{
label : '울산',
하수 : 8,
빗물 : 111,
중수도 : 19,
온배수 : 30
},
{
label : '세종',
하수 : 9,
빗물 : 65,
중수도 : 0,
온배수 : 0
},
{
label : '경기',
하수 : 176,
빗물 : 1009,
중수도 : 252,
온배수 : 40
},
{
label : '강원',
하수 : 69,
빗물 : 69,
중수도 : 22,
온배수 : 0
},
{
label : '충북',
하수 : 38,
빗물 : 17,
중수도 : 91,
온배수 : 0
},
{
label : '충남',
하수 : 67,
빗물 : 54,
중수도 : 188,
온배수 : 0
},
{
label : '전북',
하수 : 55,
빗물 : 33,
중수도 : 220,
온배수 : 0
},
{
label : '전남',
하수 : 83,
빗물 : 16,
중수도 : 75,
온배수 : 0
},
{
label : '경북',
하수 : 81,
빗물 : 37,
중수도 : 70,
온배수 : 0
},
{
label : '경남',
하수 : 75,
빗물 : 27,
중수도 : 140,
온배수 : 0
},
{
label : '제주',
하수 : 8,
빗물 : 47,
중수도 : 64,
온배수 : 0
}
]);
const chartConfig = chartData.reduce((config, element) => {
config[element.label] = {
label: element.label,
color : "hsl(var(--chart-1))"
};
return config;
}, {} as Record<string, { label: string; color: string; }>) satisfies ChartConfig;
const chartOption = {
chartForm : CHART_FORM.BAR,
chartConfig : chartConfig,
chartData : chartData,
chartTitle : '',
chartClassName : "h-[300px] w-full",
graphSize : 40,
yFieldText : '시설(개소)',
showLegend : true
}
const colorLegend = [
{ label: '하수', color: '#FF6B6B', key: 'sewage' },
{ label: '빗물', color: '#4ECDC4', key: 'rainwater' },
{ label: '중수도', color: '#45B7D1', key: 'reclaimed' },
{ label: '온배수', color: '#FED16A', key: 'thermal' },
];
const facilityTotalsColor = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#FED16A'];
const defaultYear= '2023'
const regionIdMap: Record<string, string> = {
서울: '서울특별시',
부산: '부산광역시',
대구: '대구광역시',
인천: '인천광역시',
광주: '광주광역시',
대전: '대전광역시',
울산: '울산광역시',
세종: '세종특별자치시',
경기: '경기도',
강원: '강원특별자치도',
충북: '충청북도',
충남: '충청남도',
전북: '전라북도',
전남: '전라남도',
경북: '경상북도',
경남: '경상남도',
제주: '제주특별자치도'
};
const tableData: TableData[] = [
{ region: '전국', sewage: '717(1,137,538)', rainwater: '3544(13,945)', reclaimed: '1018(222,476)', thermal: '123(492)' },
{ region: '서울특별시', sewage: '4(114,908)', rainwater: '816(430)', reclaimed: '371(341)', thermal: '0' },
{ region: '부산광역시', sewage: '13(146,197)', rainwater: '68(335)', reclaimed: '20(512)', thermal: '1(18)' },
{ region: '대구광역시', sewage: '9(102,380)', rainwater: '294(133)', reclaimed: '14(44)', thermal: '2(12)' },
{ region: '인천광역시', sewage: '17(57,691)', rainwater: '165(642)', reclaimed: '35(7,859)', thermal: '15(32)' },
{ region: '광주광역시', sewage: '3(28,738)', rainwater: '74(23)', reclaimed: '15(450)', thermal: '15(6)' },
{ region: '대전광역시', sewage: '2(11,966)', rainwater: '52(2)', reclaimed: '11(492)', thermal: '20(100)' },
{ region: '울산광역시', sewage: '8(36,076)', rainwater: '111(39)', reclaimed: '19(28,904)', thermal: '30(130)' },
{ region: '세종특별자치시', sewage: '9(2,555)', rainwater: '65(16)', reclaimed: '0(0)', thermal: '0' },
{ region: '경기도', sewage: '176(313,298)', rainwater: '1009(4,735)', reclaimed: '252(77,096)', thermal: '40(143)' },
{ region: '강원특별자치도', sewage: '69(19,677)', rainwater: '69(4)', reclaimed: '22(447)', thermal: '0' },
{ region: '충청북도', sewage: '38(15,607)', rainwater: '17(91)', reclaimed: '91(2,211)', thermal: '0' },
{ region: '충청남도', sewage: '67(41,368)', rainwater: '54(77)', reclaimed: '188(50,434)', thermal: '0' },
{ region: '전라북도', sewage: '55(42,671)', rainwater: '33(199)', reclaimed: '220(9,453)', thermal: '0' },
{ region: '전라남도', sewage: '83(23,560)', rainwater: '16(885)', reclaimed: '75(15,412)', thermal: '0' },
{ region: '경상북도', sewage: '81(129,081)', rainwater: '37(341)', reclaimed: '70(27,818)', thermal: '0' },
{ region: '경상남도', sewage: '75(50,101)', rainwater: '27(244)', reclaimed: '140(343)', thermal: '0' },
{ region: '제주특별자치도', sewage: '8(1,666)', rainwater: '47(5,746)', reclaimed: '64(660)', thermal: '0' },
];
const regionData: RegionData[] = useMemo(() => [
{ name: '서울', x: 170, y: 140, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '인천', x: 120, y: 150, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '경기', x: 210, y: 210, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '강원', x: 330, y: 120, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '충북', x: 260, y: 280, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '충남', x: 100, y: 320, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '세종', x: 180, y: 305, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '대전', x: 195, y: 360, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '전북', x: 170, y: 450, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '전남', x: 160, y: 600, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '광주', x: 120, y: 530, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '경북', x: 400, y: 320, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '경남', x: 310, y: 530, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '대구', x: 350, y: 450, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '울산', x: 450, y: 500, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '부산', x: 420, y: 550, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '제주', x: 60, y: 750, values: [0.3, 0.3, 0.2, 0.2] },
], []);
const handleMarkerClick = (regionId: string) => {
if (selectedRegion === regionId) {
@@ -242,6 +50,10 @@ const WrStatusPage: React.FC = () => {
};
useEffect(() => {
initializeCommonData();
}, [initializeCommonData]);
const createDonutMarker = useCallback((svg: SVGSVGElement, x: number, y: number, name: string, values: number[]) => {
const colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#FED16A'];
const radius = 26;
@@ -252,7 +64,6 @@ const WrStatusPage: React.FC = () => {
console.warn(`Invalid region name: ${name}`);
return;
}
const g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
g.setAttribute('transform', `translate(${x}, ${y})`);
g.setAttribute('id', `marker-${name}`);
@@ -336,6 +147,14 @@ const WrStatusPage: React.FC = () => {
svg.appendChild(g);
}, [handleMarkerClick, regionIdMap]);
useEffect(() => {
if(Common.selectSidoData&&Common.selectSidoData.length>0)
getDmStatusData(Common.selectSidoData);
},[Common.selectSidoData])
useEffect(() => {
const loadSVG = async () => {
try {
@@ -393,6 +212,31 @@ const WrStatusPage: React.FC = () => {
});
}
}, [selectedRegion]);
useEffect(() => {
if(chartData.length>0){
const chartConfig = chartData.reduce((config, element) => {
config[element.label] = {
label: element.label,
color : "hsl(var(--chart-1))"
};
return config;
}, {} as Record<string, { label: string; color: string; }>) satisfies ChartConfig;
const Option = {
chartForm : CHART_FORM.BAR,
chartConfig : chartConfig,
chartData : chartData,
chartTitle : '',
chartClassName : "w-full h-[350px] ",
graphSize : 10,
yFieldText : '시설(개소)',
showLegend : true
}
setChartOption(Option)
}else{
setChartOption({} as WrStatusChartProps)
}
}, [chartData]);
return (
<div className="flex h-screen bg-[#F2F2F2] text-gray-800">
@@ -401,7 +245,6 @@ const WrStatusPage: React.FC = () => {
{/* 상단 제목 */}
<div className="mb-6 flex justify-between items-center">
<h2 className="text-2xl font-bold">물재이용 현황</h2>
<div className="text-sm text-gray-500">관리자 ▼</div>
</div>
{/* 콘텐츠 본문 */}
@@ -410,7 +253,7 @@ const WrStatusPage: React.FC = () => {
<div className="bg-white rounded-xl shadow border border-[#DBE2E6] overflow-hidden max-h-[900px]">
{/* 타이틀 영역 */}
<div className="border-b border-[#DBE2E6] px-4 py-3">
<h3 className="text-[12px] font-semibold">재이용시설현황(2023)</h3>
<h3 className="text-[12px] font-semibold">{`재이용시설현황(${defaultYear})`}</h3>
<p className="text-[12px] text-[#999] font-medium">행정구역별 재이용시설현황(개소)</p>
</div>
@@ -439,11 +282,11 @@ const WrStatusPage: React.FC = () => {
<div className="font-semibold mb-1">{hoveredRegion}</div>
<div className="space-y-1">
{colorLegend.map(({ label, color, key }) => (
<div key={key} className="flex items-center space-x-2">
<div key={key+'' +color} className="flex items-center space-x-2">
<span className="text-[12px] inline-block w-3 h-3 rounded-sm" style={{ backgroundColor: color }}></span>
<span className="text-[12px]">
{label}:{' '}
{tableData.find(d => d.region === hoveredRegion)?.[key as keyof TableData] ?? '-'}
{statusData?.find(d => d.region === hoveredRegion)?.[key as keyof DmStatusDataType] || '-'}
</span>
</div>
))}
@@ -453,22 +296,12 @@ const WrStatusPage: React.FC = () => {
{/* 범례 */}
<div className="absolute bottom-2 right-2 bg-white rounded-lg shadow-md p-4 text-sm space-y-2">
<div className="flex items-center space-x-2">
<span className="inline-block w-4 h-4 rounded-sm" style={{backgroundColor: '#FF6B6B'}}></span>
<span className="text-[12px] text-gray-900">하수재이용시설 (총 717개소)</span>
</div>
<div className="flex items-center space-x-2">
<span className="inline-block w-4 h-4 rounded-sm" style={{backgroundColor: '#4ECDC4'}}></span>
<span className="text-[12px] text-gray-900">빗물이용시설 (총 3,730개소)</span>
</div>
<div className="flex items-center space-x-2">
<span className="inline-block w-4 h-4 rounded-sm" style={{backgroundColor: '#45B7D1'}}></span>
<span className="text-[12px] text-gray-900">중수도시설 (총 1,074개소)</span>
</div>
<div className="flex items-center space-x-2">
<span className="inline-block w-4 h-4 rounded-sm" style={{backgroundColor: '#FED16A'}}></span>
<span className="text-[12px] text-gray-900">온배수시설 (총 201개소)</span>
</div>
{facilityTotals?.map((item, index) => (
<div key ={'fcltTotal' +index}className="flex items-center space-x-2">
<span className="inline-block w-4 h-4 rounded-sm" style={{backgroundColor:facilityTotalsColor[index]}}></span>
<span className="text-[12px] text-gray-900">{item}</span>
</div>
)) }
</div>
</div>
</div>
@@ -479,10 +312,10 @@ const WrStatusPage: React.FC = () => {
{/* 재이용시설현황 표 */}
<div className="bg-white rounded-xl shadow border border-[#DBE2E6] overflow-hidden">
{/* 타이틀 + 버튼 영역 */}
<div className="flex justify-between items-center border-b border-[#DBE2E6] px-4 py-3">
<div className="flex justify-between items-center border-b border-[#436d85] px-4 py-3">
<div>
<h3 className="text-[12px] font-semibold">재이용시설현황(2023)</h3>
<p className="text-[12px] text-[#999] font-medium">행정구역별 재이용시설현황(개소)</p>
<h3 className="text-[12px] font-semibold">{`재이용시설현황(${defaultYear})`}</h3>
<p className="text-[12px] text-[#999] font-medium">행정구역별 재이용시설현황[개소(천m³/년)]</p>
</div>
</div>
<div className="p-4">
@@ -493,14 +326,17 @@ const WrStatusPage: React.FC = () => {
<tr>
<th className="text-[12px] font-semibold px-4 py-2">번호</th>
<th className="text-[12px] font-semibold px-4 py-2">시도</th>
<th className="text-[12px] font-semibold px-4 py-2">하수(이용량,천𝓂³/년)</th>
<th className="text-[12px] font-semibold px-4 py-2">하수재이용시설</th>
<th className="text-[12px] font-semibold px-4 py-2">빗물이용시설</th>
<th className="text-[12px] font-semibold px-4 py-2">중수도시설</th>
{/* <th className="text-[12px] font-semibold px-4 py-2">하수(이용량,천𝓂³/년)</th>
<th className="text-[12px] font-semibold px-4 py-2">빗물(이용량,천𝓂³/년)</th>
<th className="text-[12px] font-semibold px-4 py-2">중수도(이용량,천𝓂³/년)</th>
<th className="text-[12px] font-semibold px-4 py-2">온배수(이용량,천𝓂³/년)</th>
<th className="text-[12px] font-semibold px-4 py-2">온배수(이용량,천𝓂³/년)</th> */}
</tr>
</thead>
<tbody className="divide-y">
{tableData.map((row, index) => (
{statusData?.map((row, index) => (
<tr key={index} className="hover:bg-gray-50">
<td className="text-[12px] px-4 py-2 text-center">
{index+1}
@@ -509,7 +345,6 @@ const WrStatusPage: React.FC = () => {
<td className="text-[12px]">{row.sewage}</td>
<td className="text-[12px]">{row.rainwater}</td>
<td className="text-[12px]">{row.reclaimed}</td>
<td className="text-[12px]">{row.thermal}</td>
</tr>
))}
</tbody>
@@ -521,21 +356,23 @@ const WrStatusPage: React.FC = () => {
{/* 재이용통계 차트 */}
<div className="bg-white rounded-xl shadow border border-[#DBE2E6] overflow-hidden">
<div className="border-b border-[#DBE2E6] px-4 py-3">
<h3 className="text-[12px] font-semibold">재이용통계(2023)</h3>
<h3 className="text-[12px] font-semibold">{`재이용통계(${defaultYear})`}</h3>
<p className="text-[12px] text-[#999] font-medium">행정구역별 재이용시설 현황 개소수 그래프</p>
</div>
<div className="p-4 bg-[#f9fbfd]">
<div className="h-[305px] text-gray-500">
<MainChart
chartForm={chartOption.chartForm}
chartConfig={chartOption.chartConfig}
chartData={chartOption.chartData}
chartTitle={chartOption.chartTitle}
chartClassName={chartOption.chartClassName}
graphSize={chartOption.graphSize}
yFieldText={chartOption.yFieldText}
showLegend={chartOption.showLegend}
/>
{chartOption?
<MainChart
chartForm={chartOption.chartForm}
chartConfig={chartOption.chartConfig}
chartData={chartOption.chartData}
chartTitle={chartOption.chartTitle}
chartClassName={chartOption.chartClassName}
graphSize={chartOption.graphSize}
yFieldText={chartOption.yFieldText}
showLegend={chartOption.showLegend}
/>
:<></>}
</div>
</div>
</div>
@@ -545,5 +382,3 @@ const WrStatusPage: React.FC = () => {
</div>
);
};
export default WrStatusPage;
+65
View File
@@ -0,0 +1,65 @@
import type { RegionData, } from "../store/wrStatus/type";
export const regionData:RegionData[] = [
{ name: '서울', x: 170, y: 140, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '인천', x: 120, y: 150, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '경기', x: 210, y: 210, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '강원', x: 330, y: 120, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '충북', x: 260, y: 280, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '충남', x: 100, y: 320, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '세종', x: 180, y: 305, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '대전', x: 195, y: 360, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '전북', x: 170, y: 450, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '전남', x: 160, y: 600, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '광주', x: 120, y: 530, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '경북', x: 400, y: 320, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '경남', x: 310, y: 530, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '대구', x: 350, y: 450, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '울산', x: 450, y: 500, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '부산', x: 420, y: 550, values: [0.3, 0.3, 0.2, 0.2] },
{ name: '제주', x: 60, y: 750, values: [0.3, 0.3, 0.2, 0.2] },
]
export const regionIdMap: Record<string, string> = {
서울: '서울특별시',
부산: '부산광역시',
대구: '대구광역시',
인천: '인천광역시',
광주: '광주광역시',
대전: '대전광역시',
울산: '울산광역시',
세종: '세종특별자치시',
경기: '경기도',
강원: '강원특별자치도',
충북: '충청북도',
충남: '충청남도',
전북: '전라북도',
전남: '전라남도',
경북: '경상북도',
경남: '경상남도',
제주: '제주특별자치도'
};
export const makeRegion = (region: string) => {
if (region === '서울특별시') return '서울'
if (region === '부산광역시') return '부산'
if (region === '대구광역시') return '대구'
if (region === '인천광역시') return '인천'
if (region === '광주광역시') return '광주'
if (region === '대전광역시') return '대전'
if (region === '울산광역시') return '울산'
if (region === '세종특별자치시') return '세종'
if (region === '경기도') return '경기'
if (region === '강원특별자치도') return '강원'
if (region === '충청북도') return '충북'
if (region === '충청남도') return '충남'
if (region === '전북특별자치도') return '전북'
if (region === '전라남도') return '전남'
if (region === '경상북도') return '경북'
if (region === '경상남도') return '경남'
if (region === '제주특별자치도') return '제주'
return region;
}
+3 -5
View File
@@ -1,4 +1,4 @@
"use client"
"use client";
import "./globals.css";
export default function RootLayout({
@@ -6,15 +6,13 @@ export default function RootLayout({
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="ko">
<head>
<title>물재이용 대민</title>
</head>
<body>
{children}
</body>
<body>{children}</body>
</html>
);
}
+6 -6
View File
@@ -214,7 +214,7 @@ const selectMiddleRegionData: SelectDataType[] = [
// 시도 API 호출 함수 추가
const fetchSidoData = async (): Promise<SelectDataType[]> => {
try {
const res = await getFetch(fetchType.COMMON, '/addr/city');
const res = await getFetch(fetchType.FO, '/addr/city');
const data = res.data;
selectSidoData = [
{ text: "전체", val: '0'},
@@ -233,7 +233,7 @@ const fetchSidoData = async (): Promise<SelectDataType[]> => {
// 시군구 API 호출 함수 추가
const fetchSigunData = async (): Promise<SelectDataType[]> => {
try {
const res = await getFetch(fetchType.COMMON, '/addr/sgg');
const res = await getFetch(fetchType.FO, '/addr/sgg');
const data = res.data;
selectSigunData = [
{ text: "전체", val: '0' },
@@ -253,7 +253,7 @@ const fetchSigunData = async (): Promise<SelectDataType[]> => {
// 권역 API 호출 함수 추가
const fetchRegionData = async (): Promise<SelectDataType[]> => {
try {
const res = await getFetch(fetchType.COMMON, '/addr/sarea');
const res = await getFetch(fetchType.FO, '/addr/sarea');
const data = res.data;
return [
{ text: "전체", val: '0'},
@@ -271,7 +271,7 @@ const fetchRegionData = async (): Promise<SelectDataType[]> => {
// 중권역 API 호출 함수 추가
const fetchMiddleRegionData = async (): Promise<SelectDataType[]> => {
try {
const res = await getFetch(fetchType.COMMON, '/addr/midArea');
const res = await getFetch(fetchType.FO, '/addr/midArea');
const data = res.data;
return [
{ text: "전체", val: '0' },
@@ -290,7 +290,7 @@ const fetchMiddleRegionData = async (): Promise<SelectDataType[]> => {
// 단위유역 API 호출 함수 추가
const fetchUnitWaterShedData = async (): Promise<SelectDataType[]> => {
try {
const res = await getFetch(fetchType.COMMON, '/addr/largeArea');
const res = await getFetch(fetchType.FO, '/addr/largeArea');
const data = res.data;
return [
{ text: "전체", val: '0' },
@@ -309,7 +309,7 @@ const fetchUnitWaterShedData = async (): Promise<SelectDataType[]> => {
// 환경청 데이터
const fetchEnvPartData = async (): Promise<envPartSelectDataType[]> => {
try {
const res = await getFetch(fetchType.COMMON, '/addr/govArea');
const res = await getFetch(fetchType.FO, '/addr/govArea');
const data = res.data;
selectEnvPartData = [
{ text: "전체", val: '0', adstDliStrCd: '' },
+2 -2
View File
@@ -1,9 +1,9 @@
import { getFetch } from "@/components/ui/api";
import { fetchType, getFetch } from "@/components/ui/api";
import { DEV_URL_FO } from "@/components/ui/config";
import type { FacilityInfo, SubsInfo } from "./type";
const checkWrRegList = async () => {
const wrRegList = await getFetch("wr", `/reuseFc/pubFc`);
const wrRegList = await getFetch(fetchType.WR, `/reuseFc/pubFc`);
return wrRegList;
};
+38 -19
View File
@@ -1,29 +1,48 @@
import { createStore } from 'zustand/vanilla';
import { CommonReducer, CommonState, type CommonStore, type CommonType } from './common';
import { SdmReducer, SdmState, type SdmStore, type SdmType } from './sdmMng';
import { dmMapState, type DmMapType, type DmMapStore, DmMapReducer } from './map';
import { tokenManager } from '@/src/entities/auth/lib/token-manager';
import { createStore } from "zustand/vanilla";
import {
CommonReducer,
CommonState,
type CommonStore,
type CommonType,
} from "./common";
import { SdmReducer, SdmState, type SdmStore, type SdmType } from "./sdmMng";
import {
dmMapState,
type DmMapType,
type DmMapStore,
DmMapReducer,
} from "./map";
import { tokenManager } from "@/src/entities/auth/lib/token-manager";
import {
DmStatusReducer,
dmStatusState,
type DmStatusStore,
type DmStatusType,
} from "./wrStatus";
export type DmStore = CommonStore & SdmStore &DmMapStore ;
export type DmState = CommonType & SdmType &DmMapType;
export type DmStore = CommonStore & SdmStore & DmMapStore & DmStatusStore;
export type DmState = CommonType & SdmType & DmMapType & DmStatusType;
export const StoreZus = (initState: DmState= {
...CommonState,
...SdmState,
...dmMapState,
}) => {
export const StoreZus = (
initState: DmState = {
...CommonState,
...SdmState,
...dmMapState,
...dmStatusState,
}
) => {
return createStore<DmStore>()((set) => {
if (typeof window !== "undefined") {
tokenManager.setToken("site-id-key", 'DM');
tokenManager.setToken("site-theme-key", 'green');
tokenManager.setToken("site-id-key", "DM");
tokenManager.setToken("site-theme-key", "green");
}
return {
...initState,
...CommonReducer(set),
...SdmReducer(set),
...DmMapReducer(set)
}
})
}
...DmMapReducer(set),
...DmStatusReducer(set),
};
});
};
+122
View File
@@ -0,0 +1,122 @@
import { fetchType, getFetch } from "@/components/ui/api";
import type {
DmStatusDataType,
DmStatusChartType,
DmStatusBoardType,
} from "./type";
import type { SelectDataType } from "../common";
import { makeRegion } from "@/app/common/comFunction";
export type DmStatusActions = {
getDmStatusData(cityCd: SelectDataType[]): void;
};
export type DmStatusType = {
dmStatus: {
statusData: DmStatusDataType[];
facilityTotals: string[];
chartData: DmStatusChartType[];
};
};
export const dmStatusState: DmStatusType = {
dmStatus: {
statusData: [],
facilityTotals: [],
chartData: [],
},
};
export type DmStatusStore = DmStatusType & DmStatusActions;
export const DmStatusReducer = (set: any): DmStatusActions => {
return {
getDmStatusData: async (cityCd: SelectDataType[]) => {
const data = await getFetch(fetchType.FO, "/dashBoard/daemin");
const dataSum = data.data.reduce(
(acc: DmStatusDataType, item: DmStatusDataType) => {
acc.sewage = (
parseInt(acc.sewage.replaceAll(",", "")) +
parseInt(item.sewage.replaceAll(",", ""))
).toLocaleString();
acc.rainwater = (
parseInt(acc.rainwater.replaceAll(",", "")) +
parseInt(item.rainwater.replaceAll(",", ""))
).toLocaleString();
acc.reclaimed = (
parseInt(acc.reclaimed.replaceAll(",", "")) +
parseInt(item.reclaimed.replaceAll(",", ""))
).toLocaleString();
acc.sewageCnt = (
parseInt(acc.sewageCnt.replaceAll(",", "")) +
parseInt(item.sewageCnt.replaceAll(",", ""))
).toLocaleString();
acc.rainwaterCnt = (
parseInt(acc.rainwaterCnt.replaceAll(",", "")) +
parseInt(item.rainwaterCnt.replaceAll(",", ""))
).toLocaleString();
acc.reclaimedCnt = (
parseInt(acc.reclaimedCnt.replaceAll(",", "")) +
parseInt(item.reclaimedCnt.replaceAll(",", ""))
).toLocaleString();
return acc;
},
{
region: "합계",
sewage: "0",
rainwater: "0",
reclaimed: "0",
sewageCnt: "0",
rainwaterCnt: "0",
reclaimedCnt: "0",
}
);
data.data.unshift(dataSum);
console.log("dataSum ", dataSum);
const facilityTotals = [
"하수재이용시설" + "(총" + dataSum?.sewageCnt + "개소)",
"빗물재이용시설" + "(총" + dataSum?.rainwaterCnt + "개소)",
"중수도재이용시설" + "(총" + dataSum?.reclaimedCnt + "개소)",
];
const boardData: DmStatusBoardType[] = data.data.map(
(item: DmStatusDataType) => {
const regionText = cityCd.find((city) => item.region === city.val);
const sewage = item.sewage;
const rainwater = item.rainwater;
const reclaimed = item.reclaimed;
const sewageCnt = item.sewageCnt;
const rainwaterCnt = item.rainwaterCnt;
const reclaimedCnt = item.reclaimedCnt;
return {
region: regionText ? regionText.text : item.region,
sewage: sewageCnt + "(" + sewage + ")",
rainwater: rainwaterCnt + "(" + rainwater + ")",
reclaimed: reclaimedCnt + "(" + reclaimed + ")",
};
}
);
const chartData = data.data.map((item) => ({
label: makeRegion(
cityCd.find((city) => item.region === city.val)?.text ?? ""
),
하수: item.sewage,
빗물: item.rainwater,
중수도: item.reclaimed,
}));
set((state: DmStatusType) => ({
...state,
dmStatus: {
...state.dmStatus,
statusData: boardData,
chartData: chartData,
facilityTotals: facilityTotals,
},
}));
},
};
};
+39
View File
@@ -0,0 +1,39 @@
export type DmStatusDataType = {
region: string;
sewage: string;
rainwater: string;
reclaimed: string;
sewageCnt:string
rainwaterCnt:string
reclaimedCnt:string
};
export type DmStatusBoardType = {
region: string;
sewage: string;
rainwater: string;
reclaimed: string;
};
export type DmStatusFcltType = {
sewageFclt: string;
rainwaterFclt: string;
reclaimedFclt: string;
thermalFclt: string;
};
export type DmStatusChartType = {
label: string,
하수: string,
빗물: string,
중수도: string,
}
export type RegionData = {
name: string;
x: number;
y: number;
values: number[];
}
+3 -2
View File
@@ -3,7 +3,8 @@ import { DEV_URL_FO, DEV_URL_WR } from "../config";
export const fetchType = {
COMMON: "common",
WR: "wr"
WR: "wr",
FO:'fo'
};
interface RequestParams {
@@ -11,7 +12,7 @@ interface RequestParams {
}
export const getFetch = async (type: string, url: string) => {
const baseUrl = type === fetchType.COMMON ? DEV_URL_FO : DEV_URL_WR;
const baseUrl = type === fetchType.FO ? DEV_URL_FO : DEV_URL_WR;
const response = await fetch(baseUrl + url, {
method: "GET",
headers: {
@@ -637,7 +637,7 @@ export function SdmInfoRegForm({
}}
/>
<div className="col-span-1">
<Label className="text-xl">수소이온농도(PH)</Label>
<Label className="text-xl">수소이온농도(pH)</Label>
<div className="flex flex-row items-center gap-2">
<Input
className="!text-xl w-36"
+1 -1
View File
@@ -8,7 +8,7 @@ const GEOSERVER_URL = process.env.NEXT_PUBLIC_GEOSERVER_URL || "";
const LX_GEOSERVER_URL = process.env.NEXT_PUBLIC_LX_GEOSERVER_URL || "";
const SEWERAGE_API_URL = process.env.NEXT_PUBLIC_SEWERAGE_API_URL || "";
const BUSINESS_JUSO_API_URL = process.env.NEXT_PUBLIC_FINDADRESS_URL || "";
const AdressKey = process.env.NEXT_PUBLIC_WR_ADDRESS_KEY || "";
const AdressKey = process.env.NEXT_PRIVATE_WR_ADDRESS_KEY || "";
export function middleware(req: NextRequest) {
const pathname = req.nextUrl.pathname;
+20
View File
@@ -0,0 +1,20 @@
[
{ "region": "전국", "sewage": "717(1,137,538)", "rainwater": "3544(13,945)", "reclaimed": "1018(222,476)", "thermal": "123(492)" },
{ "region": "서울특별시", "sewage": "4(114,908)", "rainwater": "816(430)", "reclaimed": "371(341)", "thermal": "0" },
{ "region": "부산광역시", "sewage": "13(146,197)", "rainwater": "68(335)", "reclaimed": "20(512)", "thermal": "1(18)" },
{ "region": "대구광역시", "sewage": "9(102,380)", "rainwater": "294(133)", "reclaimed": "14(44)", "thermal": "2(12)" },
{ "region": "인천광역시", "sewage": "17(57,691)", "rainwater": "165(642)", "reclaimed": "35(7,859)", "thermal": "15(32)" },
{ "region": "광주광역시", "sewage": "3(28,738)", "rainwater": "74(23)", "reclaimed": "15(450)", "thermal": "15(6)" },
{ "region": "대전광역시", "sewage": "2(11,966)", "rainwater": "52(2)", "reclaimed": "11(492)", "thermal": "20(100)" },
{ "region": "울산광역시", "sewage": "8(36,076)", "rainwater": "111(39)", "reclaimed": "19(28,904)", "thermal": "30(130)" },
{ "region": "세종특별자치시", "sewage": "9(2,555)", "rainwater": "65(16)", "reclaimed": "0(0)", "thermal": "0" },
{ "region": "경기도", "sewage": "176(313,298)", "rainwater": "1009(4,735)", "reclaimed": "252(77,096)", "thermal": "40(143)" },
{ "region": "강원특별자치도", "sewage": "69(19,677)", "rainwater": "69(4)", "reclaimed": "22(447)", "thermal": "0" },
{ "region": "충청북도", "sewage": "38(15,607)", "rainwater": "17(91)", "reclaimed": "91(2,211)", "thermal": "0" },
{ "region": "충청남도", "sewage": "67(41,368)", "rainwater": "54(77)", "reclaimed": "188(50,434)", "thermal": "0" },
{ "region": "전라북도", "sewage": "55(42,671)", "rainwater": "33(199)", "reclaimed": "220(9,453)", "thermal": "0" },
{ "region": "전라남도", "sewage": "83(23,560)", "rainwater": "16(885)", "reclaimed": "75(15,412)", "thermal": "0" },
{ "region": "경상북도", "sewage": "81(129,081)", "rainwater": "37(341)", "reclaimed": "70(27,818)", "thermal": "0" },
{ "region": "경상남도", "sewage": "75(50,101)", "rainwater": "27(244)", "reclaimed": "140(343)", "thermal": "0" },
{ "region": "제주특별자치도", "sewage": "8(1,666)", "rainwater": "47(5,746)", "reclaimed": "64(660)", "thermal": "0" }
]
+19 -18
View File
@@ -1,31 +1,32 @@
# NEXT_PUBLIC_SITE_ID = WR
# NEXT_PUBLIC_PORT = 11301
# NEXT_PUBLIC_PROXY_HOST = http://con.mind-one.co.kr:11301
# NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000
# NEXT_PUBLIC_SITE_ID = FO
# NEXT_PUBLIC_PORT = 11300
# NEXT_PUBLIC_PROXY_HOST = http://con.mind-one.co.kr:11300
# NEXT_PUBLIC_SERVER_API_URL = http://con.mind-one.co.kr:11082/api/v1
# #NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000
# NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11080/api/v1
# NEXT_PUBLIC_CS_SERVER_API_URL = http://dev.onasys.co.kr:8000
# NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
# NEXT_PUBLIC_LX_GEOSERVER_URL = http://con.mind-one.co.kr:11306/geoserver
# NEXT_PUBLIC_CLAIM_NAME = Authorization
# NEXT_PUBLIC_AUTH_USER_ID = token-id
# NEXT_PUBLIC_ACCESS_TOKEN = access-token
# NEXT_PUBLIC_REFRESH_TOKEN = refresh-token
# NEXT_PUBLIC_SEWERAGE_API_URL=http://con.mind-one.co.kr:11083/sewerage-service/api # 개발 서버 API
NEXT_PUBLIC_SITE_ID = FO
NEXT_PUBLIC_PORT = 11300
NEXT_PUBLIC_PROXY_HOST = http://con.mind-one.co.kr:11300
NEXT_PUBLIC_SERVER_API_URL = http://con.mind-one.co.kr:11082/api/v1
#NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000
NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11080/api/v1
NEXT_PUBLIC_CS_SERVER_API_URL = http://dev.onasys.co.kr:8000
#NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
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_PORT = 3000
NEXT_PUBLIC_PROXY_HOST = https://larva.hasuon.or.kr
# NEXT_PUBLIC_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000
NEXT_PUBLIC_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/operation-service/api/v1
NEXT_PUBLIC_FO_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/operation-service/api/v1
NEXT_PUBLIC_CS_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000
NEXT_PUBLIC_CS_TUS_UPLOAD = /attach-service/api/v1/tus/upload
NEXT_PUBLIC_GEOSERVER_URL = http://172.29.143.87:8080/geoserver
NEXT_PUBLIC_LX_GEOSERVER_URL = http://172.29.143.87:8080/geoserver_swl
NEXT_PUBLIC_CLAIM_NAME = Authorization
NEXT_PUBLIC_AUTH_USER_ID = token-id
NEXT_PUBLIC_ACCESS_TOKEN = access-token
NEXT_PUBLIC_REFRESH_TOKEN = refresh-token
NEXT_PUBLIC_NGII_URL = http://10.98.25.94:18080/openapi/Gettile.do?apiKey=BDE2BEF39DAFEC293AB6730150F222AC
NEXT_PUBLIC_SEWERAGE_API_URL=http://con.mind-one.co.kr:11083/sewerage-service/api # 개발 서버 API
NEXT_PUBLIC_WR_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/reuse-service/api/v1
NEXT_PUBLIC_SEWERAGE_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/sewerage-service/api
@@ -0,0 +1,73 @@
/**
* 강우영향일 계산 로직
*
* 1.강우영향일 및 강우량을 계산하며 강우량이 3이상이면 강우영향일이며 이후 이틀까지 강우영향일로 포함
*
* 2.강우영향일이면서 3mm이하의 강우량일 경우에는 강우영향을 준 날의 강우량을 따름
* @param data
* @param weather (default:ALL), SUNNY, ..etc
* @author jsyang
*/
export default function CalcRainEffect(data : any, weather='ALL') {
console.log("%c Calculate RainEffect !" , "background:blue;color:white");
console.log("%c Data Length :"+data.length+" Weather : "+weather , "background:yellow;color:blue");
// 강우영향일 계산 (강우량이 3 초과이면 무조건 강우영향일)
for(let idx = 0; idx < data.length; idx++) {
const item = data[idx];
if(item){
if(item.infoRnDay && Number(item.infoRnDay) >= 3) {
item.rainEffectDay = 1;
} else {
item.rainEffectDay = 0;
}
if(item.infoRnDay == 'x'){
item.infoRnDay = '0.0';
item.toBeInfoRnDay = '0.0';
}else{
item.infoRnDay = Number(item.infoRnDay).toFixed(1);
item.toBeInfoRnDay = Number(item.infoRnDay).toFixed(1);
}
}
}
// 이틀 전, 하루 전이 강우영향일(3 이상)인 경우 해당 날도 강우영향일로 설정
for(let idx = 0; idx < data.length; idx++) {
if(data[idx]) {
// 하루 전이 강우영향일(3 이상)인 경우
if(idx > 0 && data[idx-1]?.infoRnDay && Number(data[idx-1]?.infoRnDay) >= 3) {
data[idx]!.rainEffectDay = 1;
}
// 이틀 전이 강우영향일(3 이상)인 경우
if(idx > 1 && data[idx-2]?.infoRnDay && Number(data[idx-2]?.infoRnDay) >= 3) {
data[idx]!.rainEffectDay = 1;
}
}
}
for(let idx = 0; idx < data.length; idx++) {
if(data[idx] && data[idx]?.rainEffectDay === 1) {
if(idx > 1){
if(data[idx-1]?.infoRnDay && Number(data[idx]?.infoRnDay) < 3 && Number(data[idx-1]?.infoRnDay.toString().trim()) >= 3) {
data[idx]!.toBeInfoRnDay = data[idx-1]!.infoRnDay;
}
}
if(idx > 2){
if(data[idx-2]?.infoRnDay && Number(data[idx]?.infoRnDay) < 3 && Number(data[idx-2]?.infoRnDay.toString().trim()) >= 3) {
data[idx]!.toBeInfoRnDay = data[idx-2]!.infoRnDay;
}
}
}
}
let rtnData : any = [];
if (weather === 'ALL') {
rtnData = data;
} else if (weather === 'SUNNY') {
rtnData = data.filter((item: any) => item.rainEffectDay === 0);
} else {
rtnData = data.filter((item: any) => item.rainEffectDay === 1);
}
return rtnData;
}
@@ -0,0 +1,4 @@
export default function CommaToNumber (data: any){
const rtnValue = data&&data.toString().trim()!=''&&data!=undefined?Number(data.toString().replaceAll(',','')):'';
return rtnValue;
}
+1 -1
View File
@@ -39,7 +39,7 @@ export default function DataForm({ type, column, item }: DataFormProps) {
break;
case 'float0':
if(value) {
item[column] = String(value).includes('.')?String(Math.round(parseFloat(value.toString().replace(/,/g, '')) * 1) / 1).split('.').map((part, index) =>
item[column] = item[column] = String(value).includes('.')?String(Math.round(parseFloat(value.toString().replace(/,/g, '')) * 1) / 1).split('.').map((part, index) =>
index === 0 ? part.replace(/\B(?=(\d{3})+(?!\d))/g, ",") : part
).join('.')
: String(value).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
@@ -97,26 +97,27 @@ export default function FacilityTermModalHeader<T extends { msrDt: string }>({
const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate());
const endDateOnly = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate());
const rainEffectDay = (item as T & { rainEffectDay: number }).rainEffectDay;
if(flowPanel === '2'){
const infoRnDay = (item as T & { infoRnDay: number }).infoRnDay;
const infoRnDay = (item as T & { toBeInfoRnDay: number }).toBeInfoRnDay;
return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 3 && infoRnDay < 10;
} else if(flowPanel === '3'){
const infoRnDay = (item as T & { infoRnDay: number }).infoRnDay;
const infoRnDay = (item as T & { toBeInfoRnDay: number }).toBeInfoRnDay;
return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 10 && infoRnDay < 20;
} else if(flowPanel === '4'){
const infoRnDay = (item as T & { infoRnDay: number }).infoRnDay;
const infoRnDay = (item as T & { toBeInfoRnDay: number }).toBeInfoRnDay;
return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 20 && infoRnDay < 30;
} else if(flowPanel === '5'){
const infoRnDay = (item as T & { infoRnDay: number }).infoRnDay;
const infoRnDay = (item as T & { toBeInfoRnDay: number }).toBeInfoRnDay;
return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 30 && infoRnDay < 40;
} else if(flowPanel === '6'){
const infoRnDay = (item as T & { infoRnDay: number }).infoRnDay;
const infoRnDay = (item as T & { toBeInfoRnDay: number }).toBeInfoRnDay;
return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 40 && infoRnDay < 50;
} else if(flowPanel === '7'){
const infoRnDay = (item as T & { infoRnDay: number }).infoRnDay;
const infoRnDay = (item as T & { toBeInfoRnDay: number }).toBeInfoRnDay;
return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 50 && infoRnDay < 60;
} else if(flowPanel === '8'){
const infoRnDay = (item as T & { infoRnDay: number }).infoRnDay;
const infoRnDay = (item as T & { toBeInfoRnDay: number }).toBeInfoRnDay;
return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && infoRnDay >= 60;
} else {
return (itemDateOnly >= startDateOnly && itemDateOnly <= endDateOnly) && (rainEffectDay ===1);
@@ -0,0 +1,31 @@
import React from 'react'
/**
* 하단 주석 영역
*/
type CommentType={
commentStartPoint? : string,
commentArray? : string[],
divHeight? : string,
}
function UnderComment({commentStartPoint="☞", commentArray=[], divHeight="14"} :CommentType) {
if(commentArray && commentArray.length > 0){
return (
<div className={"mt-"+divHeight}>
{commentArray.map((item, index) => (
<React.Fragment key={"comment" + index}>
<span className="text-2xl font-bold text-gray-500">
{commentStartPoint} {item}
</span>
<br/>
</React.Fragment>
))}
</div>
)
}
}
export default UnderComment;
+137
View File
@@ -0,0 +1,137 @@
# 운영실태 인수인계
## 이력
&emsp;written by yjs
&emsp;2025-
## 0. 알아두면 좋아요
&emsp;- 화면 초기 화면 : 메인 대시보드(표로 보는 대시보드)
<br>&emsp;- API swagger 주소 : http://con.mind-one.co.kr:11082/swagger-ui/index.html#
<br>&emsp;- 단위 : 유량은 정수까지 강우량은 소수점 1자리 반올림한다, 수질은 TN, TP만 소수점 3자리, 나머지는 1자리까지 반올림한다.
<br>&emsp;&emsp;▶︎ roundNumber(value:any, decimal:number) 컴포넌트를 활용해보세요!!
<br>&emsp;- 강우영향일 : 강우량이 3mm이상인 날은 강우영향일에 포함되고 하루전, 이틀전에 강우량이 3mm인 날의 경우도 강우량에 포함된다. 팝업의 강우시, 청천시 탭에서 보여주는 리스트를 만들 때 필요한 정보이니 참고한다.
<br>&emsp;&emsp;▶︎ 예시 : 1월 13일 강우량이 5일 경우 - 강우영향일 포함됨, 1월 14일, 1월 15일 강우량에 상관없이 ___강우영향일 포함됨___, 1월 16일의 경우 14일, 15일이 3mm미만이면 ___강우영향일 미포함됨___
<br>&emsp;&emsp;▶︎ CalcRainEffect(data:any, weather) 컴포넌트에서 측정일, 강우량이 포함된 데이터를 파라미터로 넘기면 강우영향일(rainEffectDay) 컬럼 및 0,1로 여부 value로 데이터에 추가되어 리턴한다.
<br>&emsp;- 운영실태는 대부분 시설의 정보를 추출해주는 화면이 대다수이며 검색은 행정별, 유역별, 환경청별로 시설을 분류하여 조회하고 엑셀, 초기화, 조회 버튼이 우측에 존재한다.
<br>&emsp;- 메인 대시보드의 경우에는 수질, 유량 등 조회하는 화면의 정보들을 압축해서 보여주는 화면이라고 생각하면 좋다. 그렇기 때문에 대시보드에서의 각각의 데이터와 메인 화면의 데이터가 일치하는지 검증하는 작업이 많이 필요하다.
<br>&emsp;- 하루 단위의 데이터를 보여주는 모달에서 연간, 하절기, 동절기, 청천시, 강우시 등의 1년치 데이터를 필터링 하여 보여주는데 탭을 누를 시 api가 재호출 되는 형식이 아니고 1년치 데이터를 필터링 하여 출력해주고 청천시탭의 경우 강우영향일은 미포함, 강우시탭의 경우 강우영향일 포함된 데이터를 보여줘야 한다.
## 1. 표로 보기(메인 대시보드)
### 1-1) 시설정보 및 운영현황
&emsp;- 년도, 시설에 해당하는 시설정보 및 유량, 수질, 물사용량 등의 정보를 표로 표출해주는 화면
<br>&emsp;- 시설계획 : 알에스원 DC-SERVICE API에서 받은 데이터를 화면에 출력
<br>&emsp;&emsp;▶︎ 주소 : 'https://apigateway.apps.rsonesoft.com/dc-service/api/v1/nowDmgMtncGnsvy';
<br>&emsp;&emsp;▶︎ 파라미터 : swtrmtFcltCd - 시설코드 / ctpvNm - 시도명 / sggNm - 시군구명 / targetYear - 대상년도
<br>&emsp;&emsp;▶︎ 리턴값(사용되는것 위주)
<br>&emsp;&emsp;&emsp;/**
<br>&emsp;&emsp;&emsp; * 증설계획
<br>&emsp;&emsp;&emsp; */
<br>&emsp;&emsp;&emsp;기승인(당초4단계), 현재, 변경1~4
<br>&emsp;&emsp;&emsp;planSwageQntSumDt4 : number | '',
<br>&emsp;&emsp;&emsp;planSwageQntSum : number | '',
<br>&emsp;&emsp;&emsp;planSwageQntSumDc1 : number | '',
<br>&emsp;&emsp;&emsp;planSwageQntSumDc2 : number | '',
<br>&emsp;&emsp;&emsp;planSwageQntSumDc3 : number | '',
<br>&emsp;&emsp;&emsp;planSwageQntSumDc4 : number | '',
<br>&emsp;&emsp;&emsp;/**
<br>&emsp;&emsp;&emsp; * 처리인구
<br>&emsp;&emsp;&emsp; */
<br>&emsp;&emsp;&emsp;// 기승인(당초4단계), 현재, 변경1~4
<br>&emsp;&emsp;&emsp;swtrmtPpltnCntDt4 : number | '',
<br>&emsp;&emsp;&emsp;swtrmtPpltnCnt : number | '',
<br>&emsp;&emsp;&emsp;swtrmtPpltnCntDc1 : number | '',
<br>&emsp;&emsp;&emsp;swtrmtPpltnCntDc2 : number | '',
<br>&emsp;&emsp;&emsp;swtrmtPpltnCntDc3 : number | '',
<br>&emsp;&emsp;&emsp;swtrmtPpltnCntDc4 : number | '',
<br>&emsp;&emsp;&emsp;/**
<br>&emsp;&emsp;&emsp; * 처리구역면적
<br>&emsp;&emsp;&emsp; */
<br>&emsp;&emsp;&emsp;// 기승인(당초4단계), 현재, 변경1~4
<br>&emsp;&emsp;&emsp;swtrmtZoneAreaDt4 : number | '',
<br>&emsp;&emsp;&emsp;swtrmtZoneArea : number | '',
<br>&emsp;&emsp;&emsp;swtrmtZoneAreaDc1 : number | '',
<br>&emsp;&emsp;&emsp;swtrmtZoneAreaDc2 : number | '',
<br>&emsp;&emsp;&emsp;swtrmtZoneAreaDc3 : number | '',
<br>&emsp;&emsp;&emsp;swtrmtZoneAreaDc4 : number | '',
<br>&emsp;&emsp;&emsp;// 처리구역
<br>&emsp;&emsp;&emsp;trtDstr : string | '',
<br>&emsp;&emsp;&emsp;
<br>&emsp;- 물사용량 : 현재 DB가 없기 때문에 해당 년도의 평균 하수유입량 * 0.65 (65%)
<br>&emsp;- 운영실태 표(우측 표)의 년도는 검색한 년도에 따라 값 설정
<br>&emsp;- 유입유량 : 순수하수유입량 + 연계처리수 + 총인설비반류수
### 1-2) 메인 그래프
&emsp;- 1년치 수질항목들의 데이터들을 표출해주는 화면
<br>&emsp;- lineBarChart, lineChart 컴포넌트를 사용하여 차트를 생성함
### 1-3) 강우일 운영현황
&emsp;- 1년치 시설의 강우량 데이터를 구간별로 일수와 강우량 정보를 표출해주는 화면
<br>&emsp;- 순수 하루단위의 강우량에 따라서 데이터를 표출하는 것이 아닌 __강우영향일__ 계산된 후 통계를 구한다.
<br>&emsp;&emsp;▶︎ 예시 : 1월 13일 강우량이 5일 경우 - 3~10mm구간 통계포함, 1월 14일 강우량이 0일 경우 - ___3~10mm구간 통계 포함___
<br>&emsp;- 설계유입수질은 처음 설계 당시의 수질 데이터이기 때문에 한개의 데이터만 추출
<br>&emsp;- 시설용량 대비는 유입유량/시설용량 * 100 (비율)
<br>&emsp;- 계의 경우 일수는 합계 그 외에는 평균값을 나타낸다.
## 2. 처리시설 현황
### 2-1) 처리시설 시설정보
&emsp;- 처리시설 정보들과 이력들을 조회할 수 있는 화면이다.
<br>&emsp;- 모달 '기본정보' 탭의 시설계획정보는 '이력관리' 탭의 이력 리스트 중 마지막 이력의 수질정보를 표출해준다.
<br>&emsp;- 모달 '이력관리' 탭에서는 이력정보와 해당 차수의 수질정보를 보여준다. (1대1)
### 2-2) 처리구역정보
&emsp;- 처리시설의 계획정보를 조회할 수 있는 화면이다.
<br>&emsp;- 1-1)의 시설계획을 참고하도록 한다. 해당 api로 계획정보를 가져온다.
<br>&emsp;- 요구사항 중 원래는 단계별로 년도를 괄호로 표시해달라는 요청사항이 있었으나 시설들마다 다르기 때문에 메인화면에 단계하단에 년도를 넣는게 불가능하다.
<br>&emsp;&emsp;▶︎ 대시보드의 계획정보 영역의 경우에는 시설코드를 파라미터로 던져 계획정보를 가져오기 때문에 가능하여 대시보드의 계획정보는 괄호로 년도를 추출하도록 한다.
## 3. 처리시설 연간 운영 현황
### 3-1) 강수현황
&emsp;- 시설별 강수현황을 조회할 수 있는 화면이다.
<br>&emsp;- 메인화면에서의 시설별 1년치 강우일, 강우일수, 강우량 데이터는 백엔드에서 계산되어 출력되는 형식이 아니라 하루치 데이터의 object(rainyDayObjList)를 store에서 계산하여 출력한다. swagger를 참고한다.
<br>&emsp;&emsp;
<br>&emsp;&emsp;data": [
<br>&emsp;&emsp;&emsp;{
<br>&emsp;&emsp;&emsp;&emsp;"bscFctCd": "11000SW001R",
<br>&emsp;&emsp;&emsp;&emsp;"bscFctNm": "난지",
<br>&emsp;&emsp;&emsp;&emsp;"sido": "서울특별시",
<br>&emsp;&emsp;&emsp;&emsp;"gugun": " ",
<br>&emsp;&emsp;&emsp;&emsp;"addr": "경기도 고양시 덕양구 현천동 692-2",
<br>&emsp;&emsp;&emsp;&emsp;"fctCpc": 860000,
<br>&emsp;&emsp;&emsp;&emsp;"stnKo": "강서",
<br>&emsp;&emsp;&emsp;&emsp;"rvbsn": "한강",
<br>&emsp;&emsp;&emsp;&emsp;"lgbsn": "한강본류",
<br>&emsp;&emsp;&emsp;&emsp;"mdmbsn": "한강서울",
<br>&emsp;&emsp;&emsp;&emsp;"rgnNm": "한강유역환경청",
<br>&emsp;&emsp;&emsp;&emsp;"totalCount": 0,
<br>&emsp;&emsp;&emsp;&emsp;"rainyDayObjList": [
<br>&emsp;&emsp;&emsp;&emsp;&emsp;{
<br>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;"bscFctCd": "11000SW001R",
<br>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;"rainDt": "2024-01-01",
<br>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;"infoRnDay": 0
<br>&emsp;&emsp;&emsp;&emsp;&emsp;},
<br>&emsp;&emsp;&emsp;&emsp;&emsp;{
<br>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;"bscFctCd": "11000SW001R",
<br>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;"rainDt": "2024-01-02",
<br>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;"infoRnDay": 0
<br>&emsp;&emsp;&emsp;&emsp;&emsp;},
<br>&emsp;&emsp;&emsp;&emsp;&emsp;.....
<br><br>&emsp;- 일별 데이터 object(rainyDayObjList)를 강우영향일 구하는 컴포넌트에 던져 강우영향일을 구한 후 메인화면에 출력해야한다.
<br>&emsp;- 모달 화면에서는 일별 데이터를 추출해 보여준다.
### 3-2) 유량현황
&emsp;- 시설별 년도별 유량현황을 조회할 수 있는 화면이다.
<br>&emsp;- 화면의 구성은 강수현황과 같이 메인화면에는 1년치 유량정보, 모달로는 하루 단위의 유량정보를 보여주지만 메인화면에서 데이터는 집계되어 추출된다.
### 3-3) 수질현황
&emsp;- 시설별 년도별 수질현황을 조회할 수 있는 화면이다.
<br>&emsp;- 2021년 이전은 COD, 21년부터는 TOC값을 표출한다. 그것을 구분하기 위해 2021년 이전의 TOC값들은 소괄호로 감싸준다.
<br>&emsp;- 모달에서 '수질 TMS'의 경우에는 운영실태 API가 아닌 물재이용 API에서 데이터를 얻으며 getFetch에서 'wr' 파라미터로 물재이용 데이터를 얻는다.
<br>&emsp;&emsp;▶︎ api 주소 : http://con.mind-one.co.kr:11080/api/v1/il/getTms/{시설번호}
## 4. 운영실태
### 4-1) 오수발생량 추정
&emsp;- 물사용량 : 원래는 연간 월별 물사용량을 연계받아서 사용해야하지만 현재 연계를 받지 못하여 하수유입량의 65%를 물사용량으로 잡았다.
<br>&emsp;- 오수전환율 : 90%로 고정
<br>&emsp;- 오수발생량 추정 : 물사용량 * (100/오수전환율)
<br>&emsp;- 연간 하수유입량과 청천시 하수유입량을 구하기 위해서 1년치 하루단위의 데이터를 가져와 계산이 필요(강우영향일 계산필요)
<br>&emsp;- 물 사용량은 월별로 연계를 받기 때문에 모달에서 하수유입량을 월별로 통계를 구해야 한다.
<br>&emsp;- 계산을 해보면 모달에서 월별 사용량의 평균과 1년치 데이터의 평균은 다르다. 직접 계산해보면 다를 수 밖에 없다. 하지만 값을 맞추기 위해서 모달에서의 평균값을 모달의 데이터가 아닌 1년치 데이터의 평균을 넣고 최대, 최소만 월별 데이터를 기반으로 구한다.
### 4-2) 지하수유입량 추정
&emsp;-적정여부 = 연간 지하수유입량/연평균 유입하수량*100
<br>&emsp;-지하수 유입량 = 하수처리장 청천시 실제유입량 - (물사용량 × 오수전환율)
<br>&emsp;-모달에서의 오수발생량 전체 평균을 구할 때 평균 하수유입량을 기반으로 한 물사용량이 아닌 현재 월 데이터에서의 평균을 구한것을 넣는다.
### 4-3) RDII분석
&emsp;-RDII 추정값 : 하절기(6~8월) 중 최저 유입 BOD일때 유입유량 x ((동절기 청천시 유입BOD - 하절기(6~8월) 중 최저 유입BOD) / (동절기 청천시 유입BOD))
<br>&emsp;- RDII 추정시 일강수량 : 하절기 최저 유입 BOD 날짜의 강우량
<br>&emsp;- 적정여부 : 하절기일 때 최저유입 BOD유입유량 > 시설용량 일 경우 초과유입 아니면 적정
@@ -1,4 +1,10 @@
"use client"
/**
* 대시보드 - 표로보기 - 배수설비 정비현황
*
* - 배수설비 현황을 조회하는 화면. 2차사업 때 예정인 화면으로 현재 사용되지 않음.
*/
"use client"
import { useFoStore } from '@/app/store';
import type { DrainageEquipmentListProps, TableUpperProps } from '@/app/store/dashboard';
@@ -1,4 +1,11 @@
"use client"
/**
* 대시보드 - 표로보기 - 시설정보 및 운영현황(모달)
*
* - 유량, 수질, 총인시설의 연간, 하절기, 동절기 단위로 값을 차트로 시각화하여 보여주는 모달화면
* - 막대그래프로 모달을 그려준다.
*/
"use client"
import type { OperationalStatusListProps } from "@/app/store/dashboard";
import { CHART_FORM, MainChart, type ChartConfig } from "@common/business_components";
import { Button } from "@common/business_components/ui/table/lib/button";
@@ -69,22 +76,12 @@ export default function DashBoardChartModal({item='', period='', title='',modalD
useEffect(() => {
if(period === 'year'){
const filteredData: yearProps[] = modalData.map((item) => {
if(waterQlty.trim().includes('T-N') || waterQlty.trim().includes('T-P')){
return {
label: item.waterQlty,
평균: typeof item.yearAvg === 'string' ? Number(item.yearAvg.replace(/,/g, '')).toFixed(3) : (item.yearAvg || 0),
최대: typeof item.yearMax === 'string' ? Number(item.yearMax.replace(/,/g, '')).toFixed(3) : (item.yearMax || 0),
최소: typeof item.yearMin === 'string' ? Number(item.yearMin.replace(/,/g, '')).toFixed(3) : (item.yearMin || 0),
평균: typeof item.yearAvg === 'string' ? Number(item.yearAvg.replace(/,/g, '')) : (item.yearAvg || 0),
최대: typeof item.yearMax === 'string' ? Number(item.yearMax.replace(/,/g, '')) : (item.yearMax || 0),
최소: typeof item.yearMin === 'string' ? Number(item.yearMin.replace(/,/g, '')) : (item.yearMin || 0),
}
}
else{
return {
label: item.waterQlty,
평균: typeof item.yearAvg === 'string' ? Number(item.yearAvg.replace(/,/g, '')).toFixed(1) : (item.yearAvg || 0),
최대: typeof item.yearMax === 'string' ? Number(item.yearMax.replace(/,/g, '')).toFixed(1) : (item.yearMax || 0),
최소: typeof item.yearMin === 'string' ? Number(item.yearMin.replace(/,/g, '')).toFixed(1) : (item.yearMin || 0),
}
}
})
if (item === 'flowRate') {
setChartData(filteredData.slice(0,5));
@@ -1,4 +1,13 @@
"use client"
/**
* 대시보드 - 표로보기 - 시설정보 및 운영현황
*
* - 시설정보 및 운영현황 탭의 메인 페이지
* - 중앙상단에는 시설에 대한 요약정보가, 좌측 상단은 시설계획에 대한 정보, 좌측하단에는 물사용량에 대한 정보,
* 우측에는 조회년도 및 시설에 해당하는 유량 및 수질정보를 연간,하절기,동절기별 추출하여 데이터를 보여준다.
* - 우측 운영실태는 연간, 하절기, 동절기별로 색이 칠해져있는데 어떤항목들끼리 차트로 그려지는지 확인하기 위해서다.
*/
"use client"
import { roundNumber } from "@/app/components/common/DataForm";
import { useFoStore } from "@/app/store";
import type { TableUpperProps } from "@/app/store/processFacility";
@@ -13,7 +22,12 @@ export type facilityInfoProps = {
fcltyList?: { bscFctCd: string, bscFctNm: string, fcltyCpc: number | '', trtFrfNm: string, efflWqltStndrdNm: string }[];
};
// 시설계획 table header 변경
/**
* 시설계획 table header 변경
* @param upHeadList
* @param planYearList
* @returns
*/
const headMakeColSpanPlanFclty = (upHeadList: TableUpperProps[], planYearList: string[]) => {
return ( <>
<TableRow>{
@@ -29,6 +43,12 @@ const headMakeColSpanPlanFclty = (upHeadList: TableUpperProps[], planYearList: s
}
// 시설계획 table header 변경
/**
*
* @param upHeadList
* @param searchYear
* @returns
*/
const headMakeColSpanOperationStatus = (upHeadList: TableUpperProps[], searchYear: string) => {
return ( <>
<TableRow>
@@ -182,7 +202,7 @@ export default function ProcessFacilitySearch({searchYear = '', fcltyList = []}:
useEffect(() => {
operationalStatusList.map((item: { [key: string]: string | number | boolean },index) => {
if(index===8 || index===9 || index===10 || index===11 || index===12 || index===13 || index===14 || index===15){
item['yearAvg'] = Number(item['yearAvg']).toFixed(3);
/* item['yearAvg'] = Number(item['yearAvg']).toFixed(3);
item['yearMax'] = item['yearMax']+'%';
item['yearMin'] = item['yearMin']+'%';
item['summerAll'] = item['summerAll']+'%';
@@ -191,7 +211,7 @@ export default function ProcessFacilitySearch({searchYear = '', fcltyList = []}:
item['winterAll'] = item['winterAll']+'%';
item['winterSunnyAvg'] = item['winterSunnyAvg']+'%';
item['winterSunnyMax'] = item['winterSunnyMax']+'%';
item['winterSunnyMin'] = item['winterSunnyMin']+'%';
item['winterSunnyMin'] = item['winterSunnyMin']+'%'; */
}
});
@@ -1,4 +1,10 @@
"use client"
/**
* 대시보드 - 표로보기 - 주요그래프
*
* - 시설의 조회년도에 해당하는 수질정보, 강우량, 유입량 등을 특정 항목별로 묶어서 차트로 시각화해주는 화면
*/
"use client"
import { useFoStore } from "@/app/store";
import type { lineChartDataProps } from "@/app/store/dashboard";
import { CHART_FORM, type ChartConfig, ContentsDiv, MainChart } from "@common/business_components";
@@ -22,10 +28,12 @@ export default function DashBoardChart({searchYear = '', fcltyList = []}: facili
const [chart_tpTp, setChart_tpTp] = useState<{
chartData1: lineChartDataProps[];
chartData2: lineChartDataProps[];
chartData3: lineChartDataProps[];
}>();
const [chart_tntn, setChart_tntn] = useState<{
chartData1: lineChartDataProps[];
chartData2: lineChartDataProps[];
chartData3: lineChartDataProps[];
}>();
const [chart_inflBodInflTn, setChart_inflBodInflTn] = useState<{
chartData1: lineChartDataProps[];
@@ -46,6 +54,7 @@ export default function DashBoardChart({searchYear = '', fcltyList = []}: facili
chart_efflTn,
chart_inflBod,
isLoadingMainGraph,
waterQltyStandartd,
} = MainGraph;
/**
@@ -60,7 +69,7 @@ export default function DashBoardChart({searchYear = '', fcltyList = []}: facili
color: colors[2],
},
lineVal0: {
label: '시설용량',
label: '지하수유입량',
color: colors[1],
},
lineVal1: {
@@ -90,6 +99,10 @@ export default function DashBoardChart({searchYear = '', fcltyList = []}: facili
label: '방류T-P',
color: colors[1],
},
chartData3: {
label : '법적방류T-P',
color : 'blackdash',
}
} satisfies ChartConfig;
// 유입T-N-방류T-N
@@ -102,6 +115,10 @@ export default function DashBoardChart({searchYear = '', fcltyList = []}: facili
label: '방류T-N',
color: colors[1],
},
chartData3: {
label : '법적방류T-N',
color : 'blackdash',
}
} satisfies ChartConfig;
// 유입BOD-유입T-N
@@ -139,21 +156,37 @@ export default function DashBoardChart({searchYear = '', fcltyList = []}: facili
useEffect(() => {
if (!chart_chongInTp || !chart_efflTp) return;
const legalTpData: lineChartDataProps[] = [];
if (waterQltyStandartd){
chart_inflTn.forEach(item =>{
legalTpData.push({label : item.label, val:waterQltyStandartd.tp});
})
}
const chartTpTpData = {
chartData1: chart_chongInTp,
chartData2: chart_efflTp
chartData2: chart_efflTp,
chartData3: legalTpData
};
setChart_tpTp(chartTpTpData);
}, [chart_chongInTp, chart_efflTp]);
}, [chart_chongInTp, chart_efflTp, chart_inflTn, waterQltyStandartd]);
useEffect(() => {
if (!chart_inflTn || !chart_efflTn) return;
const legalTnData: lineChartDataProps[] = [];
if (waterQltyStandartd){
chart_inflTn.forEach(item =>{
legalTnData.push({label : item.label, val:waterQltyStandartd.tn});
})
}
const chartTntnData = {
chartData1: chart_inflTn,
chartData2: chart_efflTn
chartData2: chart_efflTn,
chartData3: legalTnData,
};
setChart_tntn(chartTntnData);
}, [chart_inflTn, chart_efflTn]);
}, [chart_inflTn, chart_efflTn, waterQltyStandartd]);
useEffect(() => {
if (!chart_inflBod || !chart_inflTn) return;
@@ -185,21 +218,21 @@ export default function DashBoardChart({searchYear = '', fcltyList = []}: facili
<ListDiv className="h-[300px]">
<Card className="h-full">
<CardContent className="h-full">
<MainChart chartForm={CHART_FORM.LINEBAR} chartConfig={chartConfig_inflowRain} chartData={chart_inflowRain} chartTitle="유입하수량-강수량" yFieldText="유입하수량(m³/일)" yFieldText2="강수량(mm)"></MainChart>
<MainChart chartForm={CHART_FORM.LINEBAR} chartConfig={chartConfig_inflowRain} chartData={chart_inflowRain} chartTitle="유입하수량-강수량" yFieldText="유입하수량(m³/일)" yFieldText2="강수량(mm)" setXAxisYearTick={true}></MainChart>
</CardContent>
</Card>
</ListDiv>
<ListDiv className="h-[300px]">
<Card className="h-full">
<CardContent className="h-full">
<MainChart chartForm={CHART_FORM.LINEBAR} chartConfig={chartConfig_rainBod} chartData={chart_bodRain} chartTitle="유입BOD-강수량" yFieldText="BOD(mg/L)" yFieldText2="강수량(mm)"></MainChart>
<MainChart chartForm={CHART_FORM.LINEBAR} chartConfig={chartConfig_rainBod} chartData={chart_bodRain} chartTitle="유입BOD-강수량" yFieldText="BOD(mg/L)" yFieldText2="강수량(mm)" setXAxisYearTick = {true}></MainChart>
</CardContent>
</Card>
</ListDiv>
<ListDiv className="h-[300px]">
<Card className="h-full">
<CardContent className="h-full">
<MainChart chartForm={CHART_FORM.LINE} chartConfig={chartConfig_tptp} chartData={chart_tpTp} chartTitle="총인유입T-P-방류T-P" yFieldText="T-P(mg/L)"></MainChart>
<MainChart chartForm={CHART_FORM.LINE} chartConfig={chartConfig_tptp} chartData={chart_tpTp} chartTitle="총인유입T-P-방류T-P" yFieldText="T-P(mg/L)" setXAxisYearTick={true}></MainChart>
</CardContent>
</Card>
</ListDiv>
@@ -207,7 +240,7 @@ export default function DashBoardChart({searchYear = '', fcltyList = []}: facili
<ListDiv className="h-[300px]">
<Card className="h-full">
<CardContent className="h-full">
<MainChart chartForm={CHART_FORM.LINE} chartConfig={chartConfig_tntn} chartData={chart_tntn} chartTitle="유입T-N-방류T-N" yFieldText="T-N(mg/L)"></MainChart>
<MainChart chartForm={CHART_FORM.LINE} chartConfig={chartConfig_tntn} chartData={chart_tntn} chartTitle="유입T-N-방류T-N" yFieldText="T-N(mg/L)" setXAxisYearTick={true}></MainChart>
</CardContent>
</Card>
</ListDiv>
@@ -215,7 +248,7 @@ export default function DashBoardChart({searchYear = '', fcltyList = []}: facili
<ListDiv className="h-[300px]">
<Card className="h-full">
<CardContent className="h-full">
<MainChart chartForm={CHART_FORM.LINE} chartConfig={chartConfig_inflBodInflTn} chartData={chart_inflBodInflTn} chartTitle="유입BOD-유입T-N" yFieldText="농도(mg/L)"></MainChart>
<MainChart chartForm={CHART_FORM.LINE} chartConfig={chartConfig_inflBodInflTn} chartData={chart_inflBodInflTn} chartTitle="유입BOD-유입T-N" yFieldText="농도(mg/L)" setXAxisYearTick={true}></MainChart>
</CardContent>
</Card>
</ListDiv>
@@ -223,7 +256,7 @@ export default function DashBoardChart({searchYear = '', fcltyList = []}: facili
<ListDiv className="h-[300px]">
<Card className="h-full">
<CardContent className="h-full">
<MainChart chartForm={CHART_FORM.LINE} chartConfig={chartConfig_inflBodInflTp} chartData={chart_inflBodInflTp} chartTitle="유입BOD-유입T-P" yFieldText="농도(mg/L)"></MainChart>
<MainChart chartForm={CHART_FORM.LINE} chartConfig={chartConfig_inflBodInflTp} chartData={chart_inflBodInflTp} chartTitle="유입BOD-유입T-P" yFieldText="농도(mg/L)" setXAxisYearTick={true}></MainChart>
</CardContent>
</Card>
</ListDiv>
@@ -1,4 +1,10 @@
"use client"
/**
* 대시보드 - 표로보기(메인)
*
* - 대시보드 - 표로보기 메인페이지로 상단영역의 제어 및 탭 전환 시 보여주는 페이지를 지정해준다.
*/
"use client"
import { useFoStore } from "@/app/store";
import { ContentsDiv, downloadExcel, downloadMultipleExcel, filePickedBlobArray, MainDiv, SelectBox, UITab, type SelectDataType } from "@common/business_components";
import { Button, TabsContent } from "@common/components/ui";
@@ -9,6 +15,7 @@ import ProcessFacilitySearch from "./facilityInfo/page";
import DashBoardChart from "./maingraph/page";
import RainManageTab from "./rainManage/page";
import DrainageEquipment from "./drainageEquipment/page";
import { roundNumber } from "@/app/components/common/DataForm";
const tabList = [
{ value: 'facilityInfo', label: '시설정보 및 운영현황' },
@@ -17,6 +24,22 @@ const tabList = [
//{ value: 'drainageEquipment', label: '배수설비 정비현황' }
];
export const generateYearDates = (searchYear: string) => {
const dates: string[] = [];
const start = new Date(Number(searchYear), 0, 1); // 1월 1일
const end = new Date(Number(searchYear), 11, 31); // 12월 31일
for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) {
const year = d.getFullYear();
const month = String(d.getMonth() + 1).padStart(2, "0");
const day = String(d.getDate()).padStart(2, "0");
dates.push(`${year}-${month}-${day}`); // YYYY-MM-DD 형식
}
return dates;
}
export default function DashBoard() {
// 입력값 상태 관리
const { Common, initializeCommonData,searchMainGraph, searchRainManage, searchOperationStatus, OperationStatus, RainManage, MainGraph, PlanFclty } = useFoStore((state) => state);
@@ -60,11 +83,11 @@ export default function DashBoard() {
const [searchYear, setSearchYear] = useState<string>(selectSearchYear[0]?.val || '0');
// 시설명
const [fcltyList, setFcltyList] = useState<{bscFctCd: string, bscFctNm: string, fcltyCpc: number | '', trtFrfNm: string | '', efflWqltStndrdNm: string | ''}>({
bscFctCd: '26260PB001R',
bscFctNm: '수영',
fcltyCpc: 452000,
trtFrfNm: '표준활성슬러지법, MLE, MBR',
efflWqltStndrdNm: '500톤 이상(Ⅳ지역)'
bscFctCd: '11000SW001R',
bscFctNm: '난지',
fcltyCpc: 860000,
trtFrfNm: '표준활성슬러지법, MLE, A2O',
efflWqltStndrdNm: '500톤 이상(Ⅲ지역)'
});
const [searchFcltyList, setSearchFcltyList] = useState<{bscFctCd: string, bscFctNm: string, fcltyCpc: number | '', trtFrfNm: string | '', efflWqltStndrdNm: string | ''}>({
@@ -79,11 +102,11 @@ export default function DashBoard() {
if (!isInit) {
initializeCommonData();
setSearchFcltyList({
bscFctCd: '26260PB001R',
bscFctNm: '수영',
fcltyCpc: 452000,
trtFrfNm: '표준활성슬러지법, MLE, MBR',
efflWqltStndrdNm: '500톤 이상(Ⅳ지역)'
bscFctCd: '11000SW001R',
bscFctNm: '난지',
fcltyCpc: 860000,
trtFrfNm: '표준활성슬러지법, MLE, A2O',
efflWqltStndrdNm: '500톤 이상(Ⅲ지역)'
});
}
}, [isInit, initializeCommonData]);
@@ -136,7 +159,7 @@ export default function DashBoard() {
const excelData1 = planFcltyList.map((item) => {
return [
item.item,
item.provisionalApproval,
Number(item.provisionalApproval.toString().replaceAll(',',''))?Number(item.provisionalApproval.toString().replaceAll(',','')):item.provisionalApproval,
item.now,
item.stepOne,
item.stepTwo,
@@ -148,23 +171,24 @@ export default function DashBoard() {
// operationalStatusList를 2차원 배열로 변환
const excelData2 = operationalStatusList.map((item, index) => {
const baseData = [
item.yearAvg,
item.yearMax,
item.yearMin,
item.summerAll,
item.summerThree,
item.summerRain,
item.winterAll,
item.winterSunnyAvg,
item.winterSunnyMax,
item.winterSunnyMin,
item.groundWaterAvg,
item.groundWaterSummer,
item.groundWaterWinter
Number(item.yearAvg?.replaceAll(',','')),
Number(item.yearMax?.replaceAll(',','')),
Number(item.yearMin?.replaceAll(',','')),
Number(item.summerAll?.replaceAll(',','')),
Number(item.summerThree?.replaceAll(',','')),
Number(item.summerRain?.replaceAll(',','')),
Number(item.winterAll?.replaceAll(',','')),
Number(item.winterSunnyAvg?.replaceAll(',','')),
Number(item.winterSunnyMax?.replaceAll(',','')),
Number(item.winterSunnyMin?.replaceAll(',','')),
Number(item.groundWaterAvg?.replaceAll(',','').replaceAll('%','')),
Number(item.groundWaterSummer?.replaceAll(',','').replaceAll('%','')),
Number(item.groundWaterWinter?.replaceAll(',','').replaceAll('%',''))
];
// index가 0일 때만 rdi와 rdiRain 추가
return index === 0 ? [...baseData, item.rdi, item.rdiRain] : baseData;
console.log(item.rdiRain);
return index === 0 ? [...baseData, item.rdi&&item.rdi.toString().trim()!=''?Number(item.rdi.toString().replaceAll(',','')):'', item.rdiRain&&item.rdiRain.toString().trim()!=''?Number(item.rdiRain.toString().replaceAll(',','')):''] : baseData;
});
const sheetParameter = [
@@ -190,62 +214,98 @@ export default function DashBoard() {
case 'mainGraph':
searchMainGraph(searchYear, fcltyList.bscFctCd);
const yearData = generateYearDates(searchYear);
const yearValueData : any = [];
for (const i in yearData){
const rowArray: string[] = [];
rowArray.push(yearData[i] ?? "");
//강수량
rowArray.push(roundNumber(chart_inflowRain.filter(item=>{return yearData[i] === item.label})[0]?.barVal0?.toString(), 1) || '');
//유입하수량
rowArray.push(roundNumber(chart_inflowRain.filter(item=>{return yearData[i] === item.label})[0]?.lineVal1?.toString(), 0) || '');
//시설용량
rowArray.push(roundNumber(chart_inflowRain.filter(item=>{return yearData[i] === item.label})[0]?.lineVal0?.toString(), 0) || '');
//유입BOD
rowArray.push(roundNumber(chart_bodRain.filter(item=>{return yearData[i] === item.label})[0]?.lineVal0?.toString(), 1) || '');
//유입T-P
rowArray.push(roundNumber(chart_inflTp.filter(item=>{return yearData[i] === item.label})[0]?.val?.toString(), 3) || '');
//총인유입T-P
rowArray.push(roundNumber(chart_chongInTp.filter(item=>{return yearData[i] === item.label})[0]?.val?.toString(), 3) || '');
//방류T-P
rowArray.push(roundNumber(chart_efflTp.filter(item=>{return yearData[i] === item.label})[0]?.val?.toString(), 3) || '');
//유입T-N
rowArray.push(roundNumber(chart_inflTn.filter(item=>{return yearData[i] === item.label})[0]?.val?.toString(), 3) || '');
//방류T-N
rowArray.push(roundNumber(chart_efflTn.filter(item=>{return yearData[i] === item.label})[0]?.val?.toString(), 3) || '');
yearValueData.push(
rowArray
)
}
/* const excelData = [['날짜', '강수량', '유입하수량','시설용량', '유입BOD', '유입T-P', '총인유입T-P', '방류T-P'], */
const sheetParameter = [
{
data: [['날짜', '강수량'],...chart_inflowRain.map((item) => [item.label, item.barVal0])],
data: [['날짜', '강수량', '유입하수량', '지하수유입량', '유입BOD', '유입T-P','총인유입T-P', '방류T-P', '유입T-N', '방류T-N'],...yearValueData],
headerNum: 1,
headerRange: 'A1:J1',
sheetName: '주요그래프'
}
/* {
data: [['날짜', '강수량'],...chart_inflowRain.map((item) => [item.label, roundNumber(item.barVal0, 1)])],
headerNum: 1,
headerRange: 'A1:B1',
sheetName: '강수량'
},
{
data: [['날짜', '유입하수량'],...chart_inflowRain.map((item) => [item.label, item.lineVal1])],
data: [['날짜', '유입하수량'],...chart_inflowRain.map((item) => [item.label, roundNumber(item.lineVal1, 0)])],
headerNum: 1,
headerRange: 'A1:B1',
sheetName: '유입하수량'
},
{
data: [['날짜', '시설용량'],...chart_inflowRain.map((item) => [item.label, item.lineVal0])],
data: [['날짜', '시설용량'],...chart_inflowRain.map((item) => [item.label, roundNumber(item.lineVal0, 0)])],
headerNum: 1,
headerRange: 'A1:B1',
sheetName: '시설용량'
},
{
data: [['날짜', '유입BOD'],...chart_bodRain.map((item) => [item.label, item.lineVal0])],
data: [['날짜', '유입BOD'],...chart_bodRain.map((item) => [item.label, roundNumber(item.lineVal0, 1)])],
headerNum: 1,
headerRange: 'A1:B1',
sheetName: '유입BOD'
},
{
data: [['날짜', '유입T-P'],...chart_inflTp.map((item) => [item.label, item.val])],
data: [['날짜', '유입T-P'],...chart_inflTp.map((item) => [item.label, roundNumber(item.val, 3)])],
headerNum: 1,
headerRange: 'A1:B1',
sheetName: '유입T-P'
},
{
data: [['날짜', '총인유입T-P'],...chart_chongInTp.map((item) => [item.label, item.val])],
data: [['날짜', '총인유입T-P'],...chart_chongInTp.map((item) => [item.label, roundNumber(item.val, 3)])],
headerNum: 1,
headerRange: 'A1:B1',
sheetName: '총인유입T-P'
},
{
data: [['날짜', '방류T-P'],...chart_efflTp.map((item) => [item.label, item.val])],
data: [['날짜', '방류T-P'],...chart_efflTp.map((item) => [item.label, roundNumber(item.val, 3)])],
headerNum: 1,
headerRange: 'A1:B1',
sheetName: '방류T-P'
},
{
data: [['날짜', '유입T-N'],...chart_inflTn.map((item) => [item.label, item.val])],
data: [['날짜', '유입T-N'],...chart_inflTn.map((item) => [item.label, roundNumber(item.val, 3)])],
headerNum: 1,
headerRange: 'A1:B1',
sheetName: '유입T-N'
},
{
data: [['날짜', '방류T-N'],...chart_efflTn.map((item) => [item.label, item.val])],
data: [['날짜', '방류T-N'],...chart_efflTn.map((item) => [item.label, roundNumber(item.val, 3)])],
headerNum: 1,
headerRange: 'A1:B1',
sheetName: '방류T-N'
}
} */
];
downloadMultipleExcel('주요그래프', sheetParameter);
@@ -265,22 +325,22 @@ export default function DashBoard() {
const initVal = () => {
setFcltyList({
bscFctCd: '26260PB001R',
bscFctNm: '수영',
fcltyCpc: 452000,
trtFrfNm: '표준활성슬러지법, MLE, MBR',
efflWqltStndrdNm: '500톤 이상(Ⅳ지역)'
bscFctCd: '11000SW001R',
bscFctNm: '난지',
fcltyCpc: 860000,
trtFrfNm: '표준활성슬러지법, MLE, A2O',
efflWqltStndrdNm: '500톤 이상(Ⅲ지역)'
});
setSearchFcltyList({
bscFctCd: '26260PB001R',
bscFctNm: '수영',
fcltyCpc: 452000,
trtFrfNm: '표준활성슬러지법, MLE, MBR',
efflWqltStndrdNm: '500톤 이상(Ⅳ지역)'
bscFctCd: '11000SW001R',
bscFctNm: '난지',
fcltyCpc: 860000,
trtFrfNm: '표준활성슬러지법, MLE, A2O',
efflWqltStndrdNm: '500톤 이상(Ⅲ지역)'
});
setSearchYear(selectSearchYear[0]?.val || '0');
searchFcltyList.bscFctNm = '수영';
searchFcltyList.bscFctNm = '난지';
setSidoValue('0');
setSigunValue('0');
@@ -1,4 +1,11 @@
"use client"
/**
* 대시보드 - 표로보기 - 강우일 운영현황
*
* - 시설의 강우량 구간별(3~10mm미만..10~20mm미만 등) 강우일수 및 수질정보를 표로 보여주는 화면
* - 강우영향일 계산후 바뀌는 tobe강우일을 계산해야 한다.
*/
"use client"
import { useFoStore } from "@/app/store";
import { UiTable } from "@common/business_components/ui/table";
import { useEffect, useState } from "react";
@@ -46,16 +53,17 @@ export default function RainManageTab({searchYear = '', fcltyList = []}: facilit
return (
<div>
<UiTable
headName=""
tableData={rainManageList}
headlist={upHeadListRainManage}
pageSize={0}
total={0}
cellClick={undefined}
onPageChange={() => {}}
>
</UiTable>
<UiTable
headName=""
tableData={rainManageList}
headlist={upHeadListRainManage}
pageSize={0}
total={0}
cellClick={undefined}
onPageChange={() => {}}
widthFixed={true}
>
</UiTable>
<span className="text-2xl font-bold text-gray-500">☞ 일수에 강우영향일 포함됨</span>
</div>
)
@@ -1,4 +1,10 @@
"use client"
/**
* 대시보드 - 표로보기 상단구역 페에지
*
* - 대시보드 - 표로보기의 3개의 탭 상단에 조회년도, 행정정보, 시설명의 구역을 컴포넌트
*/
"use client"
import { useFoStore } from "@/app/store";
import { useEffect, useState } from "react";
import SearchInput from "../../../components/common/SearchInput";
@@ -12,7 +18,7 @@ export default function DashBoardFclty({ onFacilityChange, sidoSigun, facilityNm
} = Common;
// 시설명
const [bscFctNm, setFcltyName] = useState<string>(facilityNm || '수영');
const [bscFctNm, setFcltyName] = useState<string>(facilityNm || '난지');
const [bscFctCd, setbscFctCd] = useState<string>('11000SW001R');
const [fcltyCpc, setFcltyCpc] = useState<number | ''>(860000);
const [trtFrfNm, setTrtFrfNm] = useState<string | ''>('표준활성슬러지법, MLE, A2O');
@@ -1,9 +1,17 @@
"use client"
/**
* 처리시설 연간 운영현황 - 강수현황(모달)
*
* - 선택한 시설을 조회한 년도의 하루단위로 강우량 및 강우영향일 정보를 보여주는 화면.
*/
"use client"
import CalcRainEffect from "@/app/components/common/CalcRainEffect";
import { roundNumber } from "@/app/components/common/DataForm";
import { useFoStore } from "@/app/store";
import type { PrecipitationPropsDetailProps } from "@/app/store/facilityPrecipitation";
import { DatePickerRange, UiTable } from "@common/business_components/ui";
import { DatePickerRange, downloadExcel, UiTable } from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
import { Table, TableCell, TableHead, TableRow } from "@common/components/ui";
import { Button, Table, TableCell, TableHead, TableRow } from "@common/components/ui";
import { useEffect, useRef, useState } from "react";
type PrecipitationModalProps = {
@@ -19,16 +27,17 @@ type DateRange = {
}
export default function PrecipitationModal(props: PrecipitationModalProps) {
const { PrecipitationDetail } = useFoStore((state) => state);
const { Common, PrecipitationDetail } = useFoStore((state) => state);
const { upHeadListPrecipitationDetail } = PrecipitationDetail;
const { btnClass } = Common;
// Refs
const startPickerRef = useRef<HTMLDivElement>(null);
const endPickerRef = useRef<HTMLDivElement>(null);
// States
const [startDate, setStartDate] = useState<Date | null>(null);
const [endDate, setEndDate] = useState<Date | null>(null);
const [startDate, setStartDate] = useState<Date | undefined>(new Date());
const [endDate, setEndDate] = useState<Date | undefined>(new Date());
const didInit = useRef(false);
const [filteredDetailList, setFilteredDetailList] = useState<PrecipitationPropsDetailProps[]>([]);
const [copyDetailList, setCopyDetailList] = useState<PrecipitationPropsDetailProps[]>([]);
@@ -102,6 +111,8 @@ export default function PrecipitationModal(props: PrecipitationModalProps) {
const getTableData = () => {
const totals = calculateTotals();
totals.infoRnDay = roundNumber(totals.infoRnDay, 1);
return [
{
bscFctCd: "",
@@ -113,17 +124,20 @@ export default function PrecipitationModal(props: PrecipitationModalProps) {
};
useEffect(() => {
if(didInit.current) return;
if (props.detailList.length > 0) {
const filteredList = props.detailList.filter((item) =>
props.facilityCd === item.bscFctCd
);
setFilteredDetailList(filteredList);
setCopyDetailList(filteredList);
if (filteredList.length > 0) {
const firstDateStr = filteredList[0]?.rainDt;
const lastDateStr = filteredList[filteredList.length - 1]?.rainDt;
didInit.current = true;
const filteredList = props.detailList
.map(i => ({ ...i })) // ← 얕은 복제
.filter((item) => props.facilityCd === item.bscFctCd);
const calcData = CalcRainEffect(filteredList);
setFilteredDetailList(calcData);
setCopyDetailList(calcData);
if (calcData.length > 0) {
const firstDateStr = calcData[0]?.rainDt;
const lastDateStr = calcData[calcData.length - 1]?.rainDt;
if (firstDateStr) {
const firstDate = new Date(firstDateStr);
@@ -131,7 +145,6 @@ export default function PrecipitationModal(props: PrecipitationModalProps) {
setStartDate(firstDate);
}
}
if (lastDateStr) {
const lastDate = new Date(lastDateStr);
if (!isNaN(lastDate.getTime())) {
@@ -142,8 +155,24 @@ export default function PrecipitationModal(props: PrecipitationModalProps) {
}
}, [props.detailList, props.facilityCd]);
if (!startDate || !endDate) {
return <div>로딩 중...</div>;
const excelDownload = () => {
const totData = getTableData();
const excelDownList: any[] = [];
if(totData.length > 0){
totData.forEach((item) => {
excelDownList.push({
"날짜": item.rainDt,
"강수량(mm/일)": roundNumber(item.infoRnDay, 1),
"강우일(일)": roundNumber(item.rainDay, 0),
"강우영향일(일)": roundNumber(item.rainEffectDay, 0),
});
});
}
if (excelDownList && excelDownList.length > 0) {
downloadExcel({ data: JSON.parse(JSON.stringify(excelDownList)), fileName: props.searchYear+'년 '+props.fcltyName + ' 강수현황', sheetNameArray: ['지하수유입량'], headerRange: 'A1:D1' });
} else if (totData.length == 0) {
alert('다운받을 데이터가 없습니다.');
}
}
return (
@@ -187,6 +216,9 @@ export default function PrecipitationModal(props: PrecipitationModalProps) {
</div>
</ListDiv>
<ListDiv className="h-[550px] overflow-y-auto">
<Button className={btnClass} style={{float: 'right'}} color="green" onClick={excelDownload}>
{"엑셀다운로드"}
</Button>
<UiTable
headName={"강수현황"}
tableData={getTableData()}
@@ -196,6 +228,7 @@ export default function PrecipitationModal(props: PrecipitationModalProps) {
cellClick={undefined}
onPageChange={() => {}}
boldArray={[0]}
widthFixed={true}
/>
</ListDiv>
</>
@@ -1,4 +1,10 @@
"use client"
/**
* 처리시설 연간 운영현황 - 강수현황(메인)
*
* - 시설별 강수 현황을 조회조건대로 추출하여 표로 보여주는 화면.
*/
"use client"
import { useFoStore } from "@/app/store";
import type { TableUpperProps } from "@/app/store/common";
import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components";
@@ -6,6 +12,7 @@ import ListDiv from "@common/business_components/ui/list_div";
import { useCallback, useEffect, useRef, useState } from "react";
import PrecipitationModal from "./modal/page";
import LoadingOverlay from "@common/business_components/ui/loadingBar";
import UnderComment from "@/app/components/common/UnderComment";
export default function FacilityPrecipitation() {
const {Common
@@ -129,7 +136,7 @@ export default function FacilityPrecipitation() {
initializeCommonData();
searchFacilityPrecipitationList(1, 10, selectSearchYear[0]?.val || "0");
}
}, [isInit, initializeCommonData, searchFacilityPrecipitationList]);
}, [isInit, initializeCommonData, searchFacilityPrecipitationList, selectSearchYear]);
useEffect(() => {
if (excelList && excelList.length > 0) {
@@ -153,14 +160,6 @@ export default function FacilityPrecipitation() {
*/
// 조회
const searchFacilityPrecipitation = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => {
console.log('partValue : ', partValue);
console.log('regionValue : ', regionValue);
console.log('unitWaterShedValue : ', unitWaterShedValue);
console.log('middleRegionValue : ', middleRegionValue);
console.log('envPartValue : ', envPartValue);
console.log('sidoValue : ', sidoValue);
console.log('sigunValue : ', sigunValue);
let nameCd, partStr
switch (partValue) {
case 'R':
@@ -231,9 +230,9 @@ export default function FacilityPrecipitation() {
<LoadingOverlay isLoading={isLoading} />
<div className="h-full w-full overflow-x-scroll">
<div className={widthSize}>
<UiTable cellClick={(index: number | undefined) => index !== undefined && cellClick(index)} headName={"시설별 강수현황"} tableData={mainList} headlist={upheadList} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} />
<UiTable cellClick={(index: number | undefined) => index !== undefined && cellClick(index)} headName={"시설별 강수현황"} tableData={mainList} headlist={upheadList} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} widthFixed={true} />
</div>
<span className="text-2xl font-bold text-gray-500">☞ 강우일은 3mm 이상만 해당 / 강우영향일은 강우일 및 강우일 후 연속 2일간으로 정의</span>
<UnderComment divHeight={"3"} commentArray={["강우일은 3mm 이상만 해당 / 강우영향일은 강우일 및 강우일 후 연속 2일간으로 정의"]} />
</div>
</ListDiv>
</ContentsDiv>
@@ -1,3 +1,9 @@
/**
* 처리시설 연간 운영현황 - 수질현황
*
* - 수질현황의 헤더를 만들어주는 컴포넌트
*/
import { TableHead, TableRow } from "@common/components/ui";
interface TableUpperProps {
@@ -1,13 +1,30 @@
"use client"
/**
* 처리시설 연간 운영현황 - 수질현황
*
* - 메인화면에서 선택한 시설의 수질정보를 하루단위로 보여주는 모달.
*/
"use client"
import CommaToNumber from "@/app/components/common/CommaToNumber";
import { roundNumber } from "@/app/components/common/DataForm";
import UnderComment from "@/app/components/common/UnderComment";
import { useFoStore } from "@/app/store";
import type { FacilityWaterQltyProps, modalExcelType } from "@/app/store/facilityWaterQlty";
import { downloadExcel, UITab, UiTable } from "@common/business_components/ui";
import { downloadExcelFormat, UITab, UiTable } from "@common/business_components/ui";
import { Button, TabsContent } from "@common/components/ui";
import { useCallback, useEffect, useRef, useState } from "react";
import type { ReturnType } from "../../../../components/common/FacilityTermModalHeader";
import FacilityTermModalHeader from "../../../../components/common/FacilityTermModalHeader";
import { HeadMakeColSpan } from "../HeadMakeColSpan";
const commentArrayChungchun = [
"청천시 : 강우량이 3mm미만의 날"
];
const commentArrayRain = [
"강우량 3mm 이상만 날과 강우영향일(강우일+2일)의 날"
];
type ModalProps ={
fcltyName: string;
facilityCd : string;
@@ -39,9 +56,10 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe
searchFacilityWaterQltyListHist,
Common
} = useFoStore((state) => state);
const {btnClass} = Common;
const {btnClass, COD_YEAR} = Common;
const {
upHeadListModalYear,
upHeadListModalYearCod,
facilityWaterQltyYearList,
upHeadListModalTms,
tmsList,
@@ -64,50 +82,62 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe
let maxEfflWqltTn = 0;
let maxEfflWqltTp = 0;
let maxefflWqltToc = 0;
let maxefflWqltCod = 0;
let maxEfflWqltSs = 0;
let maxinflAssctBfrWqltBod = 0;
let maxinflAssctBfrWqltTn = 0;
let maxInflAssctBfrWqltTp = 0;
let maxinflAssctBfrWqltToc = 0;
let maxinflAssctBfrWqltCod = 0;
let maxinflAssctBfrWqltSs = 0;
let maxTpInflWqltBod = 0;
let maxTpInflWqltTp = 0;
let maxNoProcessInflAmnt = 0;
let maxInfoRnDay = 0;
// 초기값 설정
let minEfflWqltBod = filteredData.length > 0 ? parseNumber(filteredData[0]?.efflWqltBod) : 0;
let minEfflWqltTn = filteredData.length > 0 ? parseNumber(filteredData[0]?.efflWqltTn) : 0;
let minEfflWqltTp = filteredData.length > 0 ? parseNumber(filteredData[0]?.efflWqltTp) : 0;
let minefflWqltToc = filteredData.length > 0 ? parseNumber(filteredData[0]?.efflWqltToc) : 0;
let minefflWqltCod = filteredData.length > 0 ? parseNumber(filteredData[0]?.efflWqltCod) : 0;
let minEfflWqltSs = filteredData.length > 0 ? parseNumber(filteredData[0]?.efflWqltSs) : 0;
let mininflAssctBfrWqltBod = filteredData.length > 0 ? parseNumber(filteredData[0]?.inflAssctBfrWqltBod) : 0;
let mininflAssctBfrWqltTn = filteredData.length > 0 ? parseNumber(filteredData[0]?.inflAssctBfrWqltTn) : 0;
let minInflAssctBfrWqltTp = filteredData.length > 0 ? parseNumber(filteredData[0]?.inflAssctBfrWqltTp) : 0;
let mininflAssctBfrWqltToc = filteredData.length > 0 ? parseNumber(filteredData[0]?.inflAssctBfrWqltToc) : 0;
let mininflAssctBfrWqltCod = filteredData.length > 0 ? parseNumber(filteredData[0]?.inflAssctBfrWqltCod) : 0;
let mininflAssctBfrWqltSs = filteredData.length > 0 ? parseNumber(filteredData[0]?.inflAssctBfrWqltSs) : 0;
let minTpInflWqltBod = filteredData.length > 0 ? parseNumber(filteredData[0]?.tpInflWqltBod) : 0;
let minTpInflWqltTp = filteredData.length > 0 ? parseNumber(filteredData[0]?.tpInflWqltTp) : 0;
let minTpInflWqltBod = 99999999;
let minTpInflWqltTp = 99999999;
let minNoProcessInflAmnt = 99999999;
let minInfoRnDay = filteredData.length > 0 ? parseNumber(filteredData[0]?.infoRnDay) : 0;
let avgEfflWqltBod = 0;
let avgEfflWqltTn = 0;
let avgEfflWqltTp = 0;
let avgefflWqltToc = 0;
let avgefflWqltCod = 0;
let avgEfflWqltSs = 0;
let avginflAssctBfrWqltBod = 0;
let avginflAssctBfrWqltTn = 0;
let avgInflAssctBfrWqltTp = 0;
let avginflAssctBfrWqltToc = 0;
let avginflAssctBfrWqltCod = 0;
let avginflAssctBfrWqltSs = 0;
let avgTpInflWqltBod = 0;
let avgTpInflWqltTp = 0;
let tpInflWqltBodCnt = 0;
let tpInflWqltTpCnt = 0;
let avgNoProcessInflAmnt = 0;
let noProcessInflAmntCnt = 0;
let avgInfoRnDay = 0;
@@ -116,17 +146,23 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe
const efflWqltTn = parseNumber(item.efflWqltTn);
const efflWqltTp = parseNumber(item.efflWqltTp);
const efflWqltToc = parseNumber(item.efflWqltToc);
const efflWqltCod = parseNumber(item.efflWqltCod?item.efflWqltCod.replaceAll("(","").replaceAll(")",""):0);
const efflWqltSs = parseNumber(item.efflWqltSs);
const inflAssctBfrWqltBod = parseNumber(item.inflAssctBfrWqltBod);
const inflAssctBfrWqltTn = parseNumber(item.inflAssctBfrWqltTn);
const inflAssctBfrWqltTp = parseNumber(item.inflAssctBfrWqltTp);
const inflAssctBfrWqltToc = parseNumber(item.inflAssctBfrWqltToc);
const inflAssctBfrWqltCod = parseNumber(item.inflAssctBfrWqltCod?item.inflAssctBfrWqltCod.replaceAll("(","").replaceAll(")",""):0);
const inflAssctBfrWqltSs = parseNumber(item.inflAssctBfrWqltSs);
const tpInflWqltBod = parseNumber(item.tpInflWqltBod);
const tpInflWqltTp = parseNumber(item.tpInflWqltTp);
if(item.tpInflWqltBod != null && item.tpInflWqltBod.trim() != '' && item.tpInflWqltBod != undefined ){
tpInflWqltBodCnt += 1;
}
if(item.tpInflWqltTp != null && item.tpInflWqltTp.trim() != '' && item.tpInflWqltTp != undefined ){
tpInflWqltTpCnt += 1;
}
const infoRnDay = parseNumber(item.infoRnDay);
@@ -134,12 +170,14 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe
maxEfflWqltTn = Math.max(maxEfflWqltTn, efflWqltTn);
maxEfflWqltTp = Math.max(maxEfflWqltTp, efflWqltTp);
maxefflWqltToc = Math.max(maxefflWqltToc, efflWqltToc);
maxefflWqltCod = Math.max(maxefflWqltCod, efflWqltCod);
maxEfflWqltSs = Math.max(maxEfflWqltSs, efflWqltSs);
maxinflAssctBfrWqltBod = Math.max(maxinflAssctBfrWqltBod, inflAssctBfrWqltBod);
maxinflAssctBfrWqltTn = Math.max(maxinflAssctBfrWqltTn, inflAssctBfrWqltTn);
maxInflAssctBfrWqltTp = Math.max(maxInflAssctBfrWqltTp, inflAssctBfrWqltTp);
maxinflAssctBfrWqltToc = Math.max(maxinflAssctBfrWqltToc, inflAssctBfrWqltToc);
maxinflAssctBfrWqltCod = Math.max(maxinflAssctBfrWqltCod, inflAssctBfrWqltCod);
maxinflAssctBfrWqltSs = Math.max(maxinflAssctBfrWqltSs, inflAssctBfrWqltSs);
maxTpInflWqltBod = Math.max(maxTpInflWqltBod, tpInflWqltBod);
@@ -151,16 +189,24 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe
minEfflWqltTn = Math.min(minEfflWqltTn, efflWqltTn);
minEfflWqltTp = Math.min(minEfflWqltTp, efflWqltTp);
minefflWqltToc = Math.min(minefflWqltToc, efflWqltToc);
minefflWqltCod = Math.min(minefflWqltCod, efflWqltCod);
minEfflWqltSs = Math.min(minEfflWqltSs, efflWqltSs);
mininflAssctBfrWqltBod = Math.min(mininflAssctBfrWqltBod, inflAssctBfrWqltBod);
mininflAssctBfrWqltTn = Math.min(mininflAssctBfrWqltTn, inflAssctBfrWqltTn);
minInflAssctBfrWqltTp = Math.min(minInflAssctBfrWqltTp, inflAssctBfrWqltTp);
mininflAssctBfrWqltToc = Math.min(mininflAssctBfrWqltToc, inflAssctBfrWqltToc);
mininflAssctBfrWqltCod = Math.min(mininflAssctBfrWqltToc, inflAssctBfrWqltCod);
mininflAssctBfrWqltSs = Math.min(mininflAssctBfrWqltSs, inflAssctBfrWqltSs);
minTpInflWqltBod = Math.min(minTpInflWqltBod, tpInflWqltBod);
minTpInflWqltTp = Math.min(minTpInflWqltTp, tpInflWqltTp);
if(item.tpInflWqltBod != null && item.tpInflWqltBod.trim() != '' && item.tpInflWqltBod != undefined ){
minTpInflWqltBod = Math.min(minTpInflWqltBod, tpInflWqltBod);
avgTpInflWqltBod += tpInflWqltBod;
}
if(item.tpInflWqltTp != null && item.tpInflWqltTp.trim() != '' && item.tpInflWqltTp != undefined ){
minTpInflWqltTp = Math.min(minTpInflWqltTp, tpInflWqltTp);
avgTpInflWqltTp += tpInflWqltTp;
}
minInfoRnDay = Math.min(minInfoRnDay, infoRnDay);
@@ -168,16 +214,23 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe
avgEfflWqltTn += efflWqltTn;
avgEfflWqltTp += efflWqltTp;
avgefflWqltToc += efflWqltToc;
avgefflWqltCod += efflWqltCod;
avgEfflWqltSs += efflWqltSs;
avginflAssctBfrWqltBod += inflAssctBfrWqltBod;
avginflAssctBfrWqltTn += inflAssctBfrWqltTn;
avgInflAssctBfrWqltTp += inflAssctBfrWqltTp;
avginflAssctBfrWqltToc += inflAssctBfrWqltToc;
avginflAssctBfrWqltCod += inflAssctBfrWqltCod;
avginflAssctBfrWqltSs += inflAssctBfrWqltSs;
avgTpInflWqltBod += tpInflWqltBod;
avgTpInflWqltTp += tpInflWqltTp;
if(item.noProcessInflAmnt && item.noProcessInflAmnt.toString().trim() != '' && item.noProcessInflAmnt != undefined){
const noProcessInflAmnt = Number(item.noProcessInflAmnt.toString().replaceAll(',',''));
avgNoProcessInflAmnt += noProcessInflAmnt;
maxNoProcessInflAmnt = Math.max(maxNoProcessInflAmnt, noProcessInflAmnt);
minNoProcessInflAmnt = Math.min(minNoProcessInflAmnt, noProcessInflAmnt);
noProcessInflAmntCnt +=1;
}
avgInfoRnDay += infoRnDay;
});
@@ -185,16 +238,18 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe
const newFilteredData = [
{
msrDt: '평균',
efflWqltBod: filteredData.length==0?'0.0':(Math.round(avgEfflWqltBod / filteredData.length * 10) / 10).toFixed(1),
efflWqltToc: filteredData.length==0?'0.0':(Math.round(avgefflWqltToc / filteredData.length * 10) / 10).toFixed(1),
efflWqltSs: filteredData.length==0?'0.0':(Math.round(avgEfflWqltSs / filteredData.length * 10) / 10).toFixed(1),
efflWqltTn: filteredData.length==0?'0.000':(Math.round(avgEfflWqltTn / filteredData.length * 1000) / 1000).toFixed(3),
efflWqltTp: filteredData.length==0?'0.000':(Math.round(avgEfflWqltTp / filteredData.length * 1000) / 1000).toFixed(3),
inflAssctBfrWqltBod: filteredData.length==0?'0.0':(Math.round(avginflAssctBfrWqltBod / filteredData.length * 10) / 10).toFixed(1),
inflAssctBfrWqltTn: filteredData.length==0?'0.000':(Math.round(avginflAssctBfrWqltTn / filteredData.length * 1000) / 1000).toFixed(3),
inflAssctBfrWqltTp: filteredData.length==0?'0.000':(Math.round(avgInflAssctBfrWqltTp / filteredData.length * 1000) / 1000).toFixed(3),
inflAssctBfrWqltToc: filteredData.length==0?'0.0':(Math.round(avginflAssctBfrWqltToc / filteredData.length * 10) / 10).toFixed(1),
inflAssctBfrWqltSs: filteredData.length==0?'0.0':(Math.round(avginflAssctBfrWqltSs / filteredData.length * 10) / 10).toFixed(1),
efflWqltBod: filteredData.length==0 || avgEfflWqltBod===0?'0.0':roundNumber((avgEfflWqltBod / filteredData.length), 1),
efflWqltToc: filteredData.length==0 || avgefflWqltToc===0?'0.0':roundNumber((avgefflWqltToc / filteredData.length), 1),
efflWqltCod: filteredData.length==0 || avgefflWqltCod===0?"(0.0)":"("+roundNumber((avgefflWqltCod / filteredData.length), 1)+")",
efflWqltSs: filteredData.length==0 || avgEfflWqltSs===0?'0.0':roundNumber((avgEfflWqltSs / filteredData.length), 1),
efflWqltTn: filteredData.length==0 || avgEfflWqltTn ===0?'0.000':roundNumber((avgEfflWqltTn / filteredData.length), 3),
efflWqltTp: filteredData.length==0 || avgEfflWqltTp ===0?'0.000':roundNumber((avgEfflWqltTp / filteredData.length), 3),
inflAssctBfrWqltBod: filteredData.length==0 || avginflAssctBfrWqltBod===0?'0.0':roundNumber((avginflAssctBfrWqltBod / filteredData.length), 1),
inflAssctBfrWqltTn: filteredData.length==0 || avginflAssctBfrWqltTn===0?'0.000':roundNumber((avginflAssctBfrWqltTn / filteredData.length), 3),
inflAssctBfrWqltTp: filteredData.length==0 || avgInflAssctBfrWqltTp===0?'0.000':roundNumber((avgInflAssctBfrWqltTp / filteredData.length), 3),
inflAssctBfrWqltToc: filteredData.length==0 || avginflAssctBfrWqltToc===0?'0.0':roundNumber((avginflAssctBfrWqltToc / filteredData.length), 1),
inflAssctBfrWqltCod: filteredData.length==0 || avginflAssctBfrWqltCod===0?'(0.0)':"("+roundNumber((avginflAssctBfrWqltCod / filteredData.length), 1)+")",
inflAssctBfrWqltSs: filteredData.length==0 || avginflAssctBfrWqltSs===0?'0.0':roundNumber((avginflAssctBfrWqltSs / filteredData.length), 1),
bscFctCd: "",
bscFctNm: "",
lclgvrnmntNm: "",
@@ -202,22 +257,25 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe
sggNm: "",
addr: "",
fctCpc: 0,
infoRnDay: filteredData.length==0?'0.0':(Math.round(avgInfoRnDay / filteredData.length * 10) / 10).toFixed(1),
tpInflWqltBod: filteredData.length==0?'0.0':(Math.round(avgTpInflWqltBod / filteredData.length * 10) / 10).toFixed(1),
tpInflWqltTp: filteredData.length==0?'0.000':(Math.round(avgTpInflWqltTp / filteredData.length * 1000) / 1000).toFixed(3)
noProcessInflAmnt : roundNumber(avgNoProcessInflAmnt / noProcessInflAmntCnt, 0),
infoRnDay: filteredData.length==0 || avgInfoRnDay===0?'0.0':roundNumber(avgInfoRnDay / filteredData.length, 1),
tpInflWqltBod: filteredData.length==0 || avgTpInflWqltBod ===0 ?'0.0':roundNumber(avgTpInflWqltBod / tpInflWqltBodCnt, 1),
tpInflWqltTp: filteredData.length==0 || avgTpInflWqltTp === 0?'0.000':roundNumber(avgTpInflWqltTp / tpInflWqltTpCnt, 3)
},
{
msrDt : '최대',
efflWqltBod : Math.round(maxEfflWqltBod * 10) / 10?(Math.round(maxEfflWqltBod * 10) / 10).toFixed(1):'0.0',
efflWqltToc : Math.round(maxefflWqltToc * 10) / 10?(Math.round(maxefflWqltToc * 10) / 10).toFixed(1):'0.0',
efflWqltSs : Math.round(maxEfflWqltSs * 10) / 10?(Math.round(maxEfflWqltSs * 10) / 10).toFixed(1):'0.0',
efflWqltTn : Math.round(maxEfflWqltTn * 1000) / 1000?(Math.round(maxEfflWqltTn * 1000) / 1000).toFixed(3):'0.000',
efflWqltTp : Math.round(maxEfflWqltTp * 1000) / 1000?(Math.round(maxEfflWqltTp * 1000) / 1000).toFixed(3):'0.000',
inflAssctBfrWqltBod : Math.round(maxinflAssctBfrWqltBod * 10) / 10?(Math.round(maxinflAssctBfrWqltBod * 10) / 10).toFixed(1):'0.0',
inflAssctBfrWqltTn : Math.round(maxinflAssctBfrWqltTn * 1000) / 1000?(Math.round(maxinflAssctBfrWqltTn * 1000) / 1000).toFixed(3):'0.000',
inflAssctBfrWqltTp : Math.round(maxInflAssctBfrWqltTp * 1000) / 1000?(Math.round(maxInflAssctBfrWqltTp * 1000) / 1000).toFixed(3):'0.000',
inflAssctBfrWqltToc : Math.round(maxinflAssctBfrWqltToc * 10) / 10?(Math.round(maxinflAssctBfrWqltToc * 10) / 10).toFixed(1):'0.0',
inflAssctBfrWqltSs : Math.round(maxinflAssctBfrWqltSs * 10) / 10?(Math.round(maxinflAssctBfrWqltSs * 10) / 10).toFixed(1):'0.0',
efflWqltBod : Math.round(maxEfflWqltBod * 10) / 10?roundNumber(maxEfflWqltBod, 1):'0.0',
efflWqltToc : Math.round(maxefflWqltToc * 10) / 10?roundNumber(maxefflWqltToc, 1):'0.0',
efflWqltCod : Math.round(maxefflWqltCod * 10) / 10?"("+roundNumber(maxefflWqltCod, 1)+")":'(0.0)',
efflWqltSs : Math.round(maxEfflWqltSs * 10) / 10?roundNumber(maxEfflWqltSs, 1):'0.0',
efflWqltTn : Math.round(maxEfflWqltTn * 1000) / 1000?roundNumber(maxEfflWqltTn, 3):'0.000',
efflWqltTp : Math.round(maxEfflWqltTp * 1000) / 1000?roundNumber(maxEfflWqltTp, 3):'0.000',
inflAssctBfrWqltBod : Math.round(maxinflAssctBfrWqltBod * 10) / 10?roundNumber(maxinflAssctBfrWqltBod, 1):'0.0',
inflAssctBfrWqltTn : Math.round(maxinflAssctBfrWqltTn * 1000) / 1000?roundNumber(maxinflAssctBfrWqltTn, 3):'0.000',
inflAssctBfrWqltTp : Math.round(maxInflAssctBfrWqltTp * 1000) / 1000?roundNumber(maxInflAssctBfrWqltTp, 3):'0.000',
inflAssctBfrWqltToc : Math.round(maxinflAssctBfrWqltToc * 10) / 10?roundNumber(maxinflAssctBfrWqltToc, 1):'0.0',
inflAssctBfrWqltCod : Math.round(maxinflAssctBfrWqltCod * 10) / 10?"("+roundNumber(maxinflAssctBfrWqltCod, 1)+")":'(0.0)',
inflAssctBfrWqltSs : Math.round(maxinflAssctBfrWqltSs * 10) / 10?roundNumber(maxinflAssctBfrWqltSs, 1):'0.0',
bscFctCd: "",
bscFctNm: "",
lclgvrnmntNm: "",
@@ -225,22 +283,25 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe
sggNm: "",
addr: "",
fctCpc: 0,
infoRnDay: 0,
tpInflWqltBod: Math.round(maxTpInflWqltBod * 10) / 10?(Math.round(maxTpInflWqltBod * 10) / 10).toFixed(1):'0.0',
tpInflWqltTp: Math.round(maxTpInflWqltTp * 1000) / 1000?(Math.round(maxTpInflWqltTp * 1000) / 1000).toFixed(3):'0.000'
noProcessInflAmnt : roundNumber(maxNoProcessInflAmnt, 0),
infoRnDay: Math.round(maxInfoRnDay * 10) / 10?roundNumber(maxInfoRnDay, 1):'0.0',
tpInflWqltBod: Math.round(maxTpInflWqltBod * 10) / 10?roundNumber(maxTpInflWqltBod, 1):'0.0',
tpInflWqltTp: Math.round(maxTpInflWqltTp * 1000) / 1000?roundNumber(maxTpInflWqltTp, 3):'0.000'
},
{
msrDt : '최소',
efflWqltBod : Math.round(minEfflWqltBod * 10) / 10?(Math.round(minEfflWqltBod?minEfflWqltBod:0 * 10) / 10).toFixed(1) : '0.0',
efflWqltToc : Math.round(minefflWqltToc * 10) / 10?(Math.round(minefflWqltToc?minefflWqltToc:0 * 10) / 10).toFixed(1) : '0.0',
efflWqltSs : Math.round(minEfflWqltSs * 10) / 10?(Math.round(minEfflWqltSs * 10) / 10).toFixed(1) : '0.0',
efflWqltTn : Math.round(minEfflWqltTn * 1000) / 1000?(Math.round(minEfflWqltTn * 1000) / 1000).toFixed(3) : '0.000',
efflWqltTp : Math.round(minEfflWqltTp * 1000) / 1000?(Math.round(minEfflWqltTp * 1000) / 1000).toFixed(3) : '0.000',
inflAssctBfrWqltBod : Math.round(mininflAssctBfrWqltBod * 10) / 10?(Math.round(mininflAssctBfrWqltBod * 10) / 10).toFixed(1) : '0.0',
inflAssctBfrWqltTn : Math.round(mininflAssctBfrWqltTn * 1000) / 1000?(Math.round(mininflAssctBfrWqltTn * 1000) / 1000).toFixed(3) : '0.000',
inflAssctBfrWqltTp : Math.round(minInflAssctBfrWqltTp * 1000) / 1000?(Math.round(minInflAssctBfrWqltTp * 1000) / 1000).toFixed(3) : '0.000',
inflAssctBfrWqltToc : Math.round(mininflAssctBfrWqltToc * 10) / 10?(Math.round(mininflAssctBfrWqltToc * 10) / 10).toFixed(1) : '0.0',
inflAssctBfrWqltSs : Math.round(mininflAssctBfrWqltSs * 10) / 10?(Math.round(mininflAssctBfrWqltSs * 10) / 10).toFixed(1) : '0.0',
efflWqltBod : Math.round(minEfflWqltBod * 10) / 10?roundNumber(minEfflWqltBod, 1) : '0.0',
efflWqltToc : Math.round(minefflWqltToc * 10) / 10?roundNumber(minefflWqltToc, 1) : '0.0',
efflWqltCod : Math.round(minefflWqltCod * 10) / 10?"("+roundNumber(minefflWqltCod, 1)+")" : '(0.0)',
efflWqltSs : Math.round(minEfflWqltSs * 10) / 10?roundNumber(minEfflWqltSs, 1) : '0.0',
efflWqltTn : Math.round(minEfflWqltTn * 1000) / 1000?roundNumber(minEfflWqltTn, 3) : '0.000',
efflWqltTp : Math.round(minEfflWqltTp * 1000) / 1000?roundNumber(minEfflWqltTp, 3) : '0.000',
inflAssctBfrWqltBod : Math.round(mininflAssctBfrWqltBod * 10) / 10?roundNumber(mininflAssctBfrWqltBod, 1) : '0.0',
inflAssctBfrWqltTn : Math.round(mininflAssctBfrWqltTn * 1000) / 1000?roundNumber(mininflAssctBfrWqltTn, 3) : '0.000',
inflAssctBfrWqltTp : Math.round(minInflAssctBfrWqltTp * 1000) / 1000?roundNumber(minInflAssctBfrWqltTp, 3) : '0.000',
inflAssctBfrWqltToc : Math.round(mininflAssctBfrWqltToc * 10) / 10?roundNumber(mininflAssctBfrWqltToc, 1) : '0.0',
inflAssctBfrWqltCod : Math.round(mininflAssctBfrWqltCod * 10) / 10?"("+roundNumber(mininflAssctBfrWqltCod, 1)+")" : '(0.0)',
inflAssctBfrWqltSs : Math.round(mininflAssctBfrWqltSs * 10) / 10?roundNumber(mininflAssctBfrWqltSs, 1) : '0.0',
bscFctCd: "",
bscFctNm: "",
lclgvrnmntNm: "",
@@ -248,12 +309,14 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe
sggNm: "",
addr: "",
fctCpc: 0,
infoRnDay: 0,
tpInflWqltBod: Math.round(minTpInflWqltBod * 10) / 10?'0.0':(Math.round(minTpInflWqltBod * 10) / 10).toFixed(1),
tpInflWqltTp: Math.round(minTpInflWqltTp * 1000) / 1000?'0.000':(Math.round(minTpInflWqltTp * 1000) / 1000).toFixed(3)
noProcessInflAmnt : roundNumber(minNoProcessInflAmnt, 0),
infoRnDay: Math.round(minInfoRnDay * 10) / 10?'0.0':roundNumber(minInfoRnDay, 1),
tpInflWqltBod: Math.round(minTpInflWqltBod * 10) / 10 && minTpInflWqltBod != 99999999?roundNumber(minTpInflWqltBod, 1):'0.0',
tpInflWqltTp: Math.round(minTpInflWqltTp * 1000) / 1000 && minTpInflWqltTp != 99999999?roundNumber(minTpInflWqltTp, 3):'0.000'
},
...filteredData
];
return newFilteredData;
}
@@ -293,22 +356,29 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe
copyYearList.forEach((item) => {
excelDownList.push({
날짜: item.msrDt,
"유입BOD(mg/L)": item.inflAssctBfrWqltBod,
"유입TOC(COD)(mg/L)": item.inflAssctBfrWqltToc,
"유입SS(mg/L)": item.inflAssctBfrWqltSs,
"유입TN(mg/L)": item.inflAssctBfrWqltTn,
"유입TP(mg/L)": item.inflAssctBfrWqltTp,
"유출BOD(mg/L)": item.efflWqltBod,
"유출TOC(COD)(mg/L)": item.efflWqltToc,
"유출SS(mg/L)": item.efflWqltSs,
"유출TN(mg/L)": item.efflWqltTn,
"유출TP(mg/L)": item.efflWqltTp,
/* "강우량(mm/일)": item.infoRnDay?item.infoRnDay.toString():"0.0", */
"유입BOD(mg/L)": CommaToNumber(item.inflAssctBfrWqltBod),
"유입TOC(COD)(mg/L)": CommaToNumber(item.inflAssctBfrWqltToc),
"유입SS(mg/L)": CommaToNumber(item.inflAssctBfrWqltSs),
"유입TN(mg/L)": CommaToNumber(item.inflAssctBfrWqltTn),
"유입TP(mg/L)": CommaToNumber(item.inflAssctBfrWqltTp),
"유출BOD(mg/L)": CommaToNumber(item.efflWqltBod),
"유출TOC(COD)(mg/L)": CommaToNumber(item.efflWqltToc),
"유출SS(mg/L)": CommaToNumber(item.efflWqltSs),
"유출TN(mg/L)": CommaToNumber(item.efflWqltTn),
"유출TP(mg/L)": CommaToNumber(item.efflWqltTp),
"강우량(mm/일)": CommaToNumber(item.infoRnDay?item.infoRnDay.toString():"0.0"),
});
});
}
if (excelDownList && excelDownList.length > 0) {
downloadExcel({ data: JSON.parse(JSON.stringify(excelDownList)), fileName: searchYear+'년 '+fcltyName + ' 수질현황', sheetNameArray: [fcltyName + ' 수질현황'], headerRange: 'A1:K1' });
downloadExcelFormat(
{ data: JSON.parse(JSON.stringify(excelDownList))
, fileName: searchYear+'년 '+fcltyName + ' 수질현황'
, sheetNameArray: [fcltyName + ' 수질현황']
, headerRange: 'A1:L1'
, decimalArray1: [1,2,3,6,7,8,11]
, decimalArray3: [4,5,9,10]
});
} else if (prevExcelListRef.current && prevExcelListRef.current.length > 0) {
alert('다운받을 데이터가 없습니다.');
}
@@ -338,7 +408,7 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe
<UiTable
headName={undefined}
tableData={copyYearList}
headlist={upHeadListModalYear}
headlist={Number(searchYear)<COD_YEAR?upHeadListModalYearCod:upHeadListModalYear}
pageSize={0}
total={0}
cellClick={undefined}
@@ -366,7 +436,9 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe
>
<HeadMakeColSpan upHeadList={upHeadListModalTms} layoutNum={4} />
</UiTable>
{msrmtDate != yesterDayStr?.replaceAll('-','')?<h3 className="text-2xl text-left text-gray-500">※전날 데이터 결측으로 인해 가장 최근 데이터 표출함</h3> : ''}
{msrmtDate != yesterDayStr?.replaceAll('-','') ? (
<UnderComment commentArray={["전날 데이터 결측으로 인해 가장 최근 데이터 표출함"]} divHeight="0"/>
) : null}
</div>
</TabsContent>
@@ -380,11 +452,11 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe
ref={ref}
queryClick={filterData}
/>
<div className="overflow-y-auto h-[550px]">
<div className="overflow-y-auto h-[500px]">
<UiTable
headName={undefined}
tableData={copyYearList}
headlist={upHeadListModalYear}
headlist={Number(searchYear)<COD_YEAR?upHeadListModalYearCod:upHeadListModalYear}
pageSize={0}
total={0}
cellClick={undefined}
@@ -407,11 +479,11 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe
ref={ref}
queryClick={filterData}
/>
<div className="overflow-y-auto h-[550px]">
<div className="overflow-y-auto h-[500px]">
<UiTable
headName={undefined}
tableData={copyYearList}
headlist={upHeadListModalYear}
headlist={Number(searchYear)<COD_YEAR?upHeadListModalYearCod:upHeadListModalYear}
pageSize={0}
total={0}
cellClick={undefined}
@@ -434,11 +506,11 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe
ref={ref}
queryClick={filterData}
/>
<div className="overflow-y-auto h-[550px]">
<div className="overflow-y-auto h-[500px]">
<UiTable
headName={undefined}
tableData={copyYearList}
headlist={upHeadListModalYear}
headlist={Number(searchYear)<COD_YEAR?upHeadListModalYearCod:upHeadListModalYear}
pageSize={0}
total={0}
cellClick={undefined}
@@ -449,9 +521,7 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe
<HeadMakeColSpan upHeadList={upHeadListModalYear} layoutNum={3} />
</UiTable>
</div>
<div className="mt-14">
<span className="text-2xl font-bold text-gray-500">☞ 청천시 : 강우량이 3mm미만의 날</span>
</div>
<UnderComment commentArray={commentArrayChungchun} divHeight="10"/>
</TabsContent>
<TabsContent value="tab_term_rain">
@@ -464,11 +534,11 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe
ref={ref}
queryClick={filterData}
/>
<div className="overflow-y-auto h-[550px]">
<div className="overflow-y-auto h-[500px]">
<UiTable
headName={undefined}
tableData={copyYearList}
headlist={upHeadListModalYear}
headlist={Number(searchYear)<COD_YEAR?upHeadListModalYearCod:upHeadListModalYear}
pageSize={0}
total={0}
cellClick={undefined}
@@ -479,9 +549,7 @@ export default function WaterQualityModal({fcltyName='', facilityCd='', searchYe
<HeadMakeColSpan upHeadList={upHeadListModalYear} layoutNum={3} />
</UiTable>
</div>
<div className="mt-14">
<span className="text-2xl font-bold text-gray-500">☞ 강우량 3mm 이상만 날과 강우영향일(강우일+2일)의 날</span>
</div>
<UnderComment commentArray={commentArrayRain} divHeight="10"/>
</TabsContent>
</UITab>
</TabsContent>
@@ -1,13 +1,19 @@
"use client"
/**
* 처리시설 연간 운영현황 - 수질현황
*
* - 시설별 수질 현황을 조회조건대로 추출하여 표로 보여주는 화면.
*/
"use client"
import { useFoStore } from "@/app/store";
import type { TableUpperProps } from "@/app/store/common";
import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components";
import type { FacilityWaterQltyProps } from "@/app/store/facilityWaterQlty";
import { ContentsDiv, downloadExcelFormat, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components";
import ListDiv from "@common/business_components/ui/list_div";
import LoadingOverlay from "@common/business_components/ui/loadingBar";
import { useCallback, useEffect, useRef, useState } from "react";
import WaterQualityModal from "./modal/page";
import type { FacilityWaterQltyProps } from "@/app/store/facilityWaterQlty";
import LoadingOverlay from "@common/business_components/ui/loadingBar";
export default function ProcessFacilitySearch() {
const { Common
@@ -134,16 +140,27 @@ export default function ProcessFacilitySearch() {
initializeCommonData();
searchFacilityWaterQltyList(1, 10, selectSearchYear[0]?.val || "0");
}
}, [isInit, initializeCommonData, searchFacilityWaterQltyList]);
}, [isInit, initializeCommonData, searchFacilityWaterQltyList, selectSearchYear]);
useEffect(() => {
if (excelList && excelList.length > 0) {
downloadExcel({
downloadExcelFormat(
{
data: excelList as unknown as JSON[],
fileName: '시설별 수질현황',
sheetNameArray: ['시설별 수질현황'],
headerRange: 'A1:T1',
decimalArray1:[10,11,12,15,16,17],
decimalArray3:[13,14,18,19]
}
);
/* downloadExcel({
data: excelList as unknown as JSON[],
fileName: '시설별 수질현황',
sheetNameArray: ['시설별 수질현황'],
headerRange: 'A1:T1'
});
}); */
}
}, [excelList]);
@@ -163,7 +180,6 @@ export default function ProcessFacilitySearch() {
}, [searchFcltyQltyList]);
const total = facilityWaterQltyCount || 1;
console.log('total : ', total);
return (
<MainDiv>
<Title title="시설별 수질현황" />
@@ -191,7 +207,7 @@ export default function ProcessFacilitySearch() {
<LoadingOverlay isLoading={isLoading} />
<div className="h-full w-full overflow-x-scroll">
<div className={widthSize}>
<UiTable cellClick={(index: number | undefined) => index !== undefined && cellClick(index)} headName={"시설별 수질현황"} tableData={mainList} headlist={upheadList} pageSize={10} total={total<10?facilityWaterQltyList.length:total} resetPageNo={resetPage} onPageChange={handlePageChange} />
<UiTable cellClick={(index: number | undefined) => index !== undefined && cellClick(index)} headName={"시설별 수질현황"} tableData={mainList} headlist={upheadList} pageSize={10} total={total<10?facilityWaterQltyList.length:total} resetPageNo={resetPage} onPageChange={handlePageChange} widthFixed={true} />
</div>
</div>
</ListDiv>
@@ -1,4 +1,10 @@
"use client"
/**
* 처리시설 연간 운영현황 - 유량현황(모달))
*
* - 선택한 시설의 유량 정보를 하루 단위로 표로 출력해주는 모달
*/
"use client"
import FacilityTermModalHeader from "@/app/components/common/FacilityTermModalHeader";
import { useFoStore } from "@/app/store";
import type { FlowRateModalInterface, modalExcelType } from "@/app/store/flowRate";
@@ -7,6 +13,9 @@ import { Button, TabsContent } from "@common/components/ui";
import { useCallback, useEffect, useRef, useState } from "react";
import type { ReturnType } from "../../../../components/common/FacilityTermModalHeader";
import { roundUp } from "@/app/store/common";
import { roundNumber } from "@/app/components/common/DataForm";
import UnderComment from "@/app/components/common/UnderComment";
import CommaToNumber from "@/app/components/common/CommaToNumber";
const tabList = [
{ value: 'tab_term_year', label: '연간' },
@@ -59,6 +68,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st
let maxreturnAmnt = 0;
let maxefflAmnt = 0;
let maxinfoRnDay = 0;
let maxNoProcessInflAmnt = 0;
// 초기값 설정
let mintotInflAmnt = parseNumber(filteredData[0]?.totInflAmnt);
@@ -67,6 +77,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st
let minreturnAmnt = parseNumber(filteredData[0]?.returnAmnt);
let minefflAmnt = parseNumber(filteredData[0]?.efflAmnt);
let mininfoRnDay = parseNumber(filteredData[0]?.infoRnDay && filteredData[0]?.infoRnDay.toString().trim() !== 'x' ? filteredData[0]?.infoRnDay.toString().trim() : 0);
let minNoProcessInflAmnt = 99999999;
let avgtotInflAmnt = 0;
let avginflAmnt = 0;
@@ -74,8 +85,9 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st
let avgreturnAmnt = 0;
let avgefflAmnt = 0;
let avginfoRnDay = 0;
console.log('filteredData', filteredData);
let avgNoProcessInflAmnt = 0;
let noProcessInflAmntCnt = 0;
filteredData.forEach((item: FlowRateModalInterface) => {
const totInflAmnt = parseNumber(item.totInflAmnt);
const inflAmnt = parseNumber(item.inflAmnt);
@@ -83,6 +95,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st
const returnAmnt = parseNumber(item.returnAmnt);
const efflAmnt = parseNumber(item.efflAmnt);
const infoRnDay = parseNumber(item.infoRnDay && item.infoRnDay.toString().trim() !== 'x' ? item.infoRnDay.toString().trim() : 0);
maxtotInflAmnt = Math.max(maxtotInflAmnt, totInflAmnt);
maxinflAmnt = Math.max(maxinflAmnt, inflAmnt);
maxsumFlow = Math.max(maxsumFlow, sumFlow);
@@ -103,16 +116,25 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st
avgreturnAmnt += returnAmnt;
avgefflAmnt += efflAmnt;
avginfoRnDay += infoRnDay;
if(item.noProcessInflAmnt && item.noProcessInflAmnt.toString().trim() != '' && item.noProcessInflAmnt != undefined){
const noProcessInflAmnt = Number(item.noProcessInflAmnt.toString().replaceAll(',',''));
avgNoProcessInflAmnt += noProcessInflAmnt;
maxNoProcessInflAmnt = Math.max(maxNoProcessInflAmnt, noProcessInflAmnt);
minNoProcessInflAmnt = Math.min(minNoProcessInflAmnt, noProcessInflAmnt);
noProcessInflAmntCnt +=1;
}
});
const newFilteredData = [
{
msrDt: '평균',
totInflAmnt: roundUp((avgtotInflAmnt / filteredData.length), 0),
inflAmnt: roundUp((avginflAmnt / filteredData.length), 0),
sumFlow: roundUp((avgsumFlow / filteredData.length), 0),
returnAmnt: roundUp((avgreturnAmnt / filteredData.length), 0),
efflAmnt: roundUp((avgefflAmnt / filteredData.length), 0),
totInflAmnt: avgtotInflAmnt && avgtotInflAmnt!=0 ? roundUp((avgtotInflAmnt / filteredData.length), 0) : 0,
inflAmnt: avginflAmnt && avginflAmnt!=0 ? roundUp((avginflAmnt / filteredData.length), 0) : 0,
sumFlow: avgsumFlow && avgsumFlow!=0 ? roundUp((avgsumFlow / filteredData.length), 0) : 0,
returnAmnt: avgreturnAmnt && avgreturnAmnt!=0 ? roundUp((avgreturnAmnt / filteredData.length), 0) : 0,
efflAmnt: avgefflAmnt && avgefflAmnt!=0 ? roundUp((avgefflAmnt / filteredData.length), 0) : 0,
noProcessInflAmnt : roundNumber(avgNoProcessInflAmnt / noProcessInflAmntCnt, 0),
infoRnDay: avginfoRnDay > 0 ? roundUp((avginfoRnDay / filteredData.length), 1) : '0.0',
rainEffectDay: 0,
},
@@ -123,6 +145,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st
sumFlow: roundUp(maxsumFlow, 0),
returnAmnt: roundUp(maxreturnAmnt, 0),
efflAmnt: roundUp(maxefflAmnt, 0),
noProcessInflAmnt : roundNumber(maxNoProcessInflAmnt, 0),
infoRnDay: maxinfoRnDay > 0 ? roundUp(maxinfoRnDay, 1) : '0.0',
rainEffectDay: 0,
},
@@ -133,6 +156,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st
sumFlow: roundUp(minsumFlow, 0),
returnAmnt: roundUp(minreturnAmnt, 0),
efflAmnt: roundUp(minefflAmnt, 0),
noProcessInflAmnt : roundNumber(minNoProcessInflAmnt, 0),
infoRnDay: mininfoRnDay > 0 ? roundUp(mininfoRnDay, 1) : '0.0',
rainEffectDay: 0,
},
@@ -163,11 +187,11 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st
copyYearList.forEach((item) => {
excelDownList.push({
"날짜": item.msrDt,
"총유입량(m³/일)": item.totInflAmnt,
"하수유입량(m³/일)": item.inflAmnt,
"연계처리량(m³/일)": item.sumFlow,
"총인반류수량(m³/일)": item.returnAmnt,
"방류량(m³/일)": item.efflAmnt,
"총유입량(m³/일)": CommaToNumber(item.totInflAmnt),
"하수유입량(m³/일)": CommaToNumber(item.inflAmnt),
"연계처리량(m³/일)": CommaToNumber(item.sumFlow),
"총인반류수량(m³/일)": CommaToNumber(item.returnAmnt),
"방류량(m³/일)": CommaToNumber(item.efflAmnt),
/* "강우량(mm/일)": item.infoRnDay, */
});
});
@@ -281,9 +305,6 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st
boldArray={[0,1,2]}
/>
</div>
<div className="mt-14">
<span className="text-2xl font-bold text-gray-500">☞ 청천시 : 강우량이 3mm미만의 날</span>
</div>
</TabsContent>
<TabsContent value="tab_term_rain">
<FacilityTermModalHeader<FlowRateModalInterface>
@@ -298,9 +319,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st
<div className="h-[370px] overflow-y-auto overflow-x-hidden">
<UiTable headName="유량현황" tableData={copyYearList} headlist={upHeadListFlowRateModalYear} pageSize={0} total={0} cellClick={undefined} onPageChange={() => {}} className="h-[370px]" boldArray={[0,1,2]}/>
</div>
<div className="mt-14">
<span className="text-2xl font-bold text-gray-500">☞ 강우량 3mm 이상만 날과 강우영향일(강우일+2일)의 날</span>
</div>
<UnderComment commentArray={["강우량 3mm 이상만 날과 강우영향일(강우일+2일)의 날"]} />
</TabsContent>
</UITab>
</>
@@ -1,12 +1,18 @@
"use client"
/**
* 처리시설 연간 운영현황 - 유량현황
*
* - 시설별 유량 현황을 조회조건대로 추출하여 표로 보여주는 화면.
*/
"use client"
import { useFoStore } from "@/app/store";
import type { TableUpperProps } from "@/app/store/common";
import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components";
import type { ExcelType } from "@/app/store/flowRate";
import { ContentsDiv, downloadExcelFormat, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components";
import ListDiv from "@common/business_components/ui/list_div";
import LoadingOverlay from "@common/business_components/ui/loadingBar";
import { useCallback, useEffect, useRef, useState } from "react";
import FlowRateModal from "./modal/page";
import type { ExcelType } from "@/app/store/flowRate";
import LoadingOverlay from "@common/business_components/ui/loadingBar";
export default function ProcessFacilitySearch() {
const {Common
@@ -134,7 +140,7 @@ export default function ProcessFacilitySearch() {
useEffect(() => {
if (excelList && excelList.length > 0) {
downloadExcel({ data: JSON.parse(JSON.stringify(excelList)), fileName: '시설별 유량현황', sheetNameArray: ['시설별 유량현황'], headerRange: 'A1:O1' });
downloadExcelFormat({ data: JSON.parse(JSON.stringify(excelList)), fileName: '시설별 유량현황', sheetNameArray: ['시설별 유량현황'], headerRange: 'A1:O1', decimalArray0: [9,10,11,12,13,14] });
} else if (prevExcelListRef.current && prevExcelListRef.current.length > 0) {
alert('다운받을 데이터가 없습니다.');
}
@@ -192,7 +198,7 @@ export default function ProcessFacilitySearch() {
<LoadingOverlay isLoading={isLoading} />
<div className="h-full w-full overflow-x-scroll">
<div className={widthSize}>
<UiTable cellClick={(index: number | undefined) => index !== undefined && cellClick(index)} headName={"시설별 유량현황"} tableData={flowRateList} headlist={upheadList} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} />
<UiTable cellClick={(index: number | undefined) => index !== undefined && cellClick(index)} headName={"시설별 유량현황"} tableData={flowRateList} headlist={upheadList} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} widthFixed={true} />
</div>
</div>
</ListDiv>
@@ -1,11 +1,24 @@
"use client"
/**
* 처리시설 연간 운영현황 - 계획하수량 산정지표 현황
*
* - 시설별 여유용량, 변동부하율, 분류식화율을 조회조건대로 추출하여 표로 보여주는 화면.
*/
"use client"
import { useFoStore } from "@/app/store";
import type { TableUpperProps } from "@/app/store/common";
import { downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiTable, type ReturnType } from "@common/business_components";
import ListDiv from "@common/business_components/ui/list_div";
import { useCallback, useEffect, useRef, useState } from "react";
import LoadingOverlay from "@common/business_components/ui/loadingBar";
import UnderComment from "@/app/components/common/UnderComment";
const commentArray = [
"여유용량 = 하수처리시설 시설용량 – 건기시 유입유량(평균)​",
"변동부하율 = 건기시 일최대 유량/일평균​유량(기준 최근 3개년)​",
"분류식화율 = 분류식지역 면적(㎢) / 처리​구역 면적합계(㎢) ×100"
]
export default function PlanSewage() {
const {Common
,PlanSewage
@@ -104,10 +117,9 @@ export default function PlanSewage() {
initializeCommonData();
searchPlanSewageList(1, 10, selectSearchYear[0]?.val || "0", ref.current.partValue);
}
}, [isInit, initializeCommonData, searchPlanSewageList]);
}, [isInit, initializeCommonData, searchPlanSewageList, selectSearchYear]);
useEffect(() => {
console.log('excelList' , excelList);
if (excelList && excelList.length > 0) {
downloadExcel({
data: excelList as unknown as JSON[],
@@ -136,12 +148,14 @@ export default function PlanSewage() {
default:
if(sidoValue !== '0') nameCd = sidoValue;
if(sigunValue !== '0') nameCd = sigunValue;
partStr = envPartValue !== '0' ? envPartValue:partValue;
break;
partStr = envPartValue !== '0' ? envPartValue:partValue;
break;
}
if (partStr.length > 1 || fcltCpct !== '0' || operationValue!== '0' ||nameCd ||(fcltyName.trim() !== "" && fcltyName.trim() !== null)) {
searchPlanSewageList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined);
} else {
// G로 넘기면 데이터가 안떠서 환경청 전체로 넘기면 전체를 추출하기위해서...
partValue = partValue==='G'?'A':partValue;
searchPlanSewageList(pageNo, pageCnt, searchYear, partValue);
}
}, [operationValue, fcltyName, searchPlanSewageList, searchYear, fcltCpct]);
@@ -192,13 +206,9 @@ export default function PlanSewage() {
<LoadingOverlay isLoading={isLoading} />
<div className="h-full w-full overflow-x-scroll">
<div className={widthSize}>
<UiTable cellClick={ undefined } headName={"계획하수량 산정지표 현황"} tableData={mainList} headlist={upheadList} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} />
</div>
<div className="mt-14">
<span className="text-2xl font-bold text-gray-500">☞ 여유용량 = 하수처리시설 시설용량 – 건기시 유입유량(평균)​</span><br/>
<span className="text-2xl font-bold text-gray-500">☞ 변동부하율 = 건기시 일최대 유량/일평균​유량(기준 최근 3개년)​</span><br/>
<span className="text-2xl font-bold text-gray-500">☞ 분류식화율 = 분류식지역 면적(㎢) / 처리​구역 면적합계(㎢) ×100</span><br/>
<UiTable cellClick={ undefined } headName={"계획하수량 산정지표 현황"} tableData={mainList} headlist={upheadList} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} widthFixed={true} />
</div>
<UnderComment divHeight={"5"} commentArray={commentArray} />
</div>
</ListDiv>
</MainDiv>
@@ -1,4 +1,10 @@
"use client"
/**
* 처리시설 현황 - 처리구역정보(모달)
*
* - 선택한 시설의 계획정보를 가져와 표로 출력해주는 모달
*/
"use client"
import { useFoStore } from "@/app/store";
import { UiTable } from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
@@ -1,4 +1,10 @@
"use client"
/**
* 처리시설 현황 - 처리구역정보(메인)
*
* - 시설계획 정보를 조회조건대로 추출하여 표로 보여주는 화면.
*/
"use client"
import { useFoStore } from "@/app/store";
import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components";
import ListDiv from "@common/business_components/ui/list_div";
@@ -157,7 +163,7 @@ export default function ProcessArea() {
<LoadingOverlay isLoading={isLoading} />
<div className="h-full w-full overflow-x-scroll">
<div className="w-[180%]">
<UiTable cellClick={(index: number | undefined) => index !== undefined && cellClick(index)} headName={"처리구역정보"} tableData={mainList} headlist={upHeadList1} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} />
<UiTable cellClick={(index: number | undefined) => index !== undefined && cellClick(index)} headName={"처리구역정보"} tableData={mainList} headlist={upHeadList1} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} widthFixed={true} />
</div>
</div>
</ListDiv>
@@ -1,12 +1,18 @@
"use client"
/**
* 처리시설 현황 - 처리시설 시설정보(모달))
*
* - 선택한 시설의 정보와 시설이력정보를 보여주는 모달.
*/
"use client"
import { useFoStore } from "@/app/store";
import type { TableUpperProps } from "@/app/store/dashboard";
import { UITab, UiTable } from "@common/business_components/ui";
import { downloadExcelFormat, filePickedBlobArray, UITab, UiTable } from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
import {
TabsContent
} from "@common/components";
import { Table, TableCell, TableHead, TableRow } from "@common/components/ui";
import { Button, Table, TableCell, TableHead, TableRow } from "@common/components/ui";
type ModalType = {
fcltyName: string;
@@ -82,8 +88,8 @@ const headMakeList = (upHeadList: TableUpperProps[], gridNum:number) => {
export default function ProcessFacilityInfoModal(props: ModalType) {
// 그리드 관련
const {ProcessFacilityDetail} = useFoStore((state) => state);
const {Common, ProcessFacilityDetail} = useFoStore((state) => state);
const { btnClass } = Common;
const {
upHeadListPlanInfo,
gridListPlanInfo,
@@ -111,10 +117,82 @@ export default function ProcessFacilityInfoModal(props: ModalType) {
{ value: 'common_info', label: '기본정보' },
{ value: 'history_info', label: '이력정보' },
];
const fctCpc = props.fctCpc ? props.fctCpc.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") : '';
const fctCpc = props.fctCpc ? Number(props.fctCpc).toLocaleString() : '';
const upHeadListPlanInfoChange = headMakeList(upHeadListPlanInfo, 2);
const upHeadListFcltyHistInfoChange = headMakeList(upHeadListFcltyHistInfo, 3);
const upHeadListFcltyWaterQltyInfoChange = headMakeList(upHeadListFcltyWaterQltyInfo, 4);
const excelDownloadPlan = () => {
const excelDownList: any[] = [];
if(gridListFcltyHistInfo.length > 0){
gridListFcltyHistInfo.forEach((item) => {
excelDownList.push({
"차수": item.extnsSeqno,
"구분": item.extnsNm,
"사업시작일": item.bzStrtYrMnth,
"사업종료일": item.bzEdYrMnth,
"설치인가일": item.eqpPrmsDt,
"준공일": item.cmplDt,
"시운전완료일": item.trlrnCmplDt,
"가동개시일": item.rnDt,
"시설용량(m³/일)": item.fctCpc&&item.fctCpc.toString().trim()!=''?Number(item.fctCpc.toString().replaceAll(',','')):'',
});
});
}
if (excelDownList && excelDownList.length > 0) {
downloadExcelFormat({ data: JSON.parse(JSON.stringify(excelDownList)), fileName: props.fcltyName + ' 시설이력관리', sheetNameArray: [props.fcltyName + ' 시설이력관리'], headerRange: 'A1:I1' });
} else if (gridListFcltyHistInfo.length == 0) {
alert('다운받을 데이터가 없습니다.');
}
}
const excelDownloadQlty = () => {
fetch(`/dashBoadModalWaterQlty.xlsx`, {}).then(async (response) => {
if (!response.ok) {
throw Error(response.statusText);
}
// 받은 파일 바인너리 처리
const blobRet = await response.arrayBuffer();
const excelData = gridListFcltyWaterQltyInfo.map((item) => {
return [
item.extnsSeqno,
item.plInflWqltBod,
item.plInflWqltToc,
item.plInflWqltCod,
item.plInflWqltSs,
item.plInflWqltTn,
item.plInflWqltTp,
item.dsInflWqltBod,
item.dsInflWqltToc,
item.dsInflWqltCod,
item.dsInflWqltSs,
item.dsInflWqltTn,
item.dsInflWqltTp,
item.plEfflWqltBod,
item.plEfflWqltToc,
item.plEfflWqltCod,
item.plEfflWqltSs,
item.plEfflWqltTn,
item.plEfflWqltTp,
];
});
const sheetParameter = [
{
data: excelData,
headerNum: 2,
headerRange: 'A1:S2',
sheetName: '시설 수질정보',
startCol: 'A'
},
];
// 버퍼에 있는 엑셀데이터 전달 후 json으로 변환
await filePickedBlobArray(blobRet, props.fcltyName +' 수질정보', sheetParameter);
});
}
return (
<>
<ListDiv className="!h-[80px]">
@@ -132,7 +210,7 @@ export default function ProcessFacilityInfoModal(props: ModalType) {
</div>
</ListDiv>
<div className="overflow-y-auto">
<div className="!h-[600px]">
<div className="h-[550px]">
<ListDiv className="">
<UITab tabList={tabList} defaultValue="common_info">
<TabsContent value="common_info">
@@ -144,9 +222,9 @@ export default function ProcessFacilityInfoModal(props: ModalType) {
<thead>
<TableRow className="">
<TableHead className="w-1/6">{'시설명'}</TableHead>
<TableCell className="w-1/6">{props.fcltyName}</TableCell>
<TableHead className="w-1/6">{'시설구분'}</TableHead>
<TableCell className="w-1/6">{props.bscFctClsNm}</TableCell>
<TableCell className="w-1/6" colSpan={3}>{props.fcltyName}</TableCell>
{/* <TableHead className="w-1/6">{'시설구분'}</TableHead>
<TableCell className="w-1/6">{props.bscFctClsNm}</TableCell> */}
<TableHead className="w-1/6">{'시설용량(m³/일)'}</TableHead>
<TableCell className="w-1/6">{fctCpc}</TableCell>
</TableRow>
@@ -184,8 +262,11 @@ export default function ProcessFacilityInfoModal(props: ModalType) {
<TabsContent value="history_info">
<ListDiv>
<div className="h-[270px] w-full overflow-y-auto overflow-x-hidden">
<div className="h-[130%]">
<div className="h-[250px] w-full overflow-y-auto overflow-x-hidden">
<Button className={btnClass} style={{float: 'right'}} color="green" onClick={excelDownloadPlan}>
{"엑셀다운로드"}
</Button>
<div className="h-[120%]">
<UiTable headName={"시설 이력관리"} tableData={gridListFcltyHistInfo} headlist={upHeadListFcltyHistInfo} pageSize={0} total={0} cellClick={undefined} onPageChange={()=>{}}>
{upHeadListFcltyHistInfoChange}
</UiTable>
@@ -193,8 +274,11 @@ export default function ProcessFacilityInfoModal(props: ModalType) {
</div>
</ListDiv>
<ListDiv>
<div className="h-[270px] w-full overflow-y-auto overflow-x-hidden">
<div className="h-[130%]">
<div className="h-[250px] w-full overflow-y-auto overflow-x-hidden">
<Button className={btnClass} style={{float: 'right'}} color="green" onClick={excelDownloadQlty}>
{"엑셀다운로드"}
</Button>
<div className="h-[120%]">
<UiTable headName={"시설 수질정보"} tableData={gridListFcltyWaterQltyInfo} headlist={upHeadListFcltyWaterQltyInfo} pageSize={0} total={0} cellClick={undefined} onPageChange={()=>{}}>
{upHeadListFcltyWaterQltyInfoChange}
</UiTable>
@@ -1,11 +1,17 @@
"use client"
import { HeadMakeColSpan } from "@/app/components/common/HeadMakeColSpan";
/**
* 처리시설 현황 - 처리시설 시설정보(메인)
*
* - 시설별 정보를 조회조건대로 추출하여 표로 보여주는 화면.
*/
"use client"
import UnderComment from "@/app/components/common/UnderComment";
import { useFoStore } from "@/app/store";
import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components";
import ListDiv from "@common/business_components/ui/list_div";
import LoadingOverlay from "@common/business_components/ui/loadingBar";
import { useCallback, useEffect, useRef, useState } from "react";
import ProcessFacilityInfoModal from "./modal/page";
import LoadingOverlay from "@common/business_components/ui/loadingBar";
export default function ProcessFacilitySearch() {
const {Common
@@ -204,12 +210,13 @@ export default function ProcessFacilitySearch() {
const cellClick = (index: number) => {
const facility = processFacilityList[index];
if (facility) {
const fctCpc = String(facility.fctCpc).replace(/,/g, "").trim();
setModalFcltyNm(facility.bscFctNm);
setModalFcltyCd(facility.bscFctCd);
setModalSido(facility.sido);
setModalGugun(facility.gugun);
setModalAddr(facility.daddr);
setModalFctCpc(Number(facility.fctCpc));
setModalFctCpc(Number(fctCpc));
setModalTrtFrfNm(facility.trtFrfNm);
setModalRnDt(facility.rnDt);
setModalCmplDt(facility.cmplDt);
@@ -274,13 +281,13 @@ export default function ProcessFacilitySearch() {
total={total}
resetPageNo={resetPage}
onPageChange={changePage}
widthFixed={true}
>
<HeadMakeColSpan upHeadList={upHeadList} layoutNum={partValue}/>
</UiTable>
</div>
<UnderComment divHeight={"0"} commentArray={["계획유입수질 및 설계유입수질은 해당 BOD를 나타냄"]} />
</div>
</ListDiv>
<span className="text-2xl text-gray-500">※계획유입수질 및 설계유입수질은 해당 BOD를 나타냄</span>
</ContentsDiv>
{selectedRow !== null && (
<UiModal
+18 -6
View File
@@ -1,10 +1,22 @@
"use client"
/**
* 운영실태 - RDII 추정
*
* - 시설별 유입량과 하절기 최저 유입 BOD 정보를 통해 RDII를 추정치를 보여주는 화면
*/
"use client"
import { useFoStore } from "@/app/store";
import type { TableUpperProps } from "@/app/store/common";
import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiTable, type ReturnType } from "@common/business_components";
import ListDiv from "@common/business_components/ui/list_div";
import { useCallback, useEffect, useRef, useState } from "react";
import LoadingOverlay from "@common/business_components/ui/loadingBar";
import UnderComment from "@/app/components/common/UnderComment";
const commentArray = [
"강우시 총 추정유입량 = 청천시 유입하수량 + RDII 추정값",
"주) 처리장 유입부에서 측정된 유량 및 수질조사 자료를 기준으로 산정된 결과임"
]
export default function Rdi() {
const {Common
@@ -60,7 +72,7 @@ export default function Rdi() {
// 초기화 변수
const [resetPage, setResetPage] = useState<boolean>(false);
// 표 너비
const [widthSize, setWidthSize] = useState<string>("w-[120%]");
const [widthSize, setWidthSize] = useState<string>("w-[130%]");
// 구분별 그리드 헤더
const [upheadList, setUpheadList] = useState<TableUpperProps[]>(upHeadList1);
// 용량별
@@ -107,7 +119,7 @@ export default function Rdi() {
initializeCommonData();
searchRdiList(1, 10, selectSearchYear[0]?.val || "0");
}
}, [isInit, initializeCommonData, searchRdiList]);
}, [isInit, initializeCommonData, searchRdiList, selectSearchYear]);
useEffect(() => {
if (excelList && excelList.length > 0) {
@@ -149,7 +161,7 @@ export default function Rdi() {
}, [operationValue, fcltyName, searchRdiList, searchYear, fcltCpct]);
const chkVal = useCallback((returntype:ReturnType) => {
setWidthSize(returntype.partValue=='A' ?"w-[120%]":"w-[130%]")
setWidthSize(returntype.partValue=='A' ?"w-[130%]":"w-[150%]")
setUpheadList(returntype.partValue == 'R' ? upHeadList2 : returntype.partValue == 'G'?upHeadList3:upHeadList1);
setResetPage(true);
}, [upHeadList1, upHeadList2, upHeadList3]);
@@ -195,9 +207,9 @@ export default function Rdi() {
<LoadingOverlay isLoading={isLoading} />
<div className="h-full w-full overflow-x-scroll">
<div className={widthSize}>
<UiTable cellClick={ undefined } headName={"RDII추정"} tableData={mainList} headlist={upheadList} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} />
<UiTable cellClick={ undefined } headName={"RDII추정"} tableData={mainList} headlist={upheadList} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} widthFixed={true} />
</div>
<span className="text-2xl text-gray-500">※주) 처리장 유입부에서 측정된 유량 및 수질조사 자료를 기준으로 산정된 결과임</span>
<UnderComment divHeight={"0"} commentArray={commentArray} />
</div>
</ListDiv>
</ContentsDiv>
@@ -1,15 +1,23 @@
"use client"
/**
* 운영실태 - 오수발생량 추정(모달)
*
* - 선택한 시설의 물사용량과 오수전환율을 가지고 오수발생량 추정 데이터를 월별로 보여주는 모달.
*/
"use client"
import { roundNumber } from "@/app/components/common/DataForm";
import { useFoStore } from "@/app/store";
import type { modalTableType } from "@/app/store/sewageOccur";
import { DateMonthPicker, UiTable } from "@common/business_components/ui";
import { DateMonthPicker, downloadExcel, UiTable } from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
import { Table, TableCell, TableHead, TableRow } from "@common/components/ui";
import { Button, Table, TableCell, TableHead, TableRow } from "@common/components/ui";
import { useEffect, useState } from "react";
export default function SewageOccurModal(props: { fcltyName: string; facilityCd : string; searchYear : string}) {
// 그리드 관련
const {SewageOccurDetail, searchSewageOccurDetailList} = useFoStore((state) => state);
const { Common, SewageOccurDetail, searchSewageOccurDetailList} = useFoStore((state) => state);
const { btnClass } = Common;
// searchYear 유효성 검사 및 기본값 설정
const validSearchYear = props.searchYear && /^\d{4}$/.test(props.searchYear) ? props.searchYear : new Date().getFullYear().toString();
@@ -61,6 +69,25 @@ export default function SewageOccurModal(props: { fcltyName: string; facilityCd
}
}, [endYearMonth, startYearMonth]);
const excelDownload = () => {
const excelDownList: any[] = [];
if(detailList.length > 0){
detailList.forEach((item) => {
excelDownList.push({
"날짜": item.msrDt,
"물사용량(m³/일)": roundNumber(item.waterUsage, 0),
"오수전환율(%)": roundNumber(item.swageChangePercent, 0),
"오수발생량 추정(m³/일)": roundNumber(item.estimationSewage, 0),
});
});
}
if (excelDownList && excelDownList.length > 0) {
downloadExcel({ data: JSON.parse(JSON.stringify(excelDownList)), fileName: props.searchYear+'년 '+props.fcltyName + ' 오수발생량 추정', sheetNameArray: [props.fcltyName + ' 오수발생량 추정'], headerRange: 'A1:D1' });
} else if (detailList.length == 0) {
alert('다운받을 데이터가 없습니다.');
}
}
return (
<>
<ListDiv className="!h-[80px] !mt-10">
@@ -118,7 +145,10 @@ export default function SewageOccurModal(props: { fcltyName: string; facilityCd
</ListDiv>
<ListDiv className="!h-[570px] overflow-y-auto">
<div className="h-[120%]">
<UiTable headName={"오수발생량 추정"} tableData={detailList} headlist={upHeadListSewageOccurDetail} pageSize={0} total={0} cellClick={undefined} onPageChange={() => {}} boldArray={[0, 1, 2]}>
<Button className={btnClass} style={{float: 'right'}} color="green" onClick={excelDownload}>
{"엑셀다운로드"}
</Button>
<UiTable headName={"오수발생량 추정"} tableData={detailList} headlist={upHeadListSewageOccurDetail} pageSize={0} total={0} cellClick={undefined} onPageChange={() => {}} boldArray={[0, 1, 2]} widthFixed={true} >
</UiTable>
</div>
</ListDiv>
@@ -1,4 +1,11 @@
"use client"
/**
* 운영실태 - 오수발생량 추정(메인)
*
* - 조회조건대로 시설별 물 사용량과 오수전환율을 기반으로 오수발생량 추정치를 표로 보여주는 화면
* - 현재 물사용량의 경우 연계받는 데이터가 아닌 연 하수유입량의 65%로 가정하고 계산함
*/
"use client"
import { useFoStore } from "@/app/store";
import type { TableUpperProps } from "@/app/store/common";
import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components";
@@ -222,7 +229,7 @@ export default function PlanSewage() {
<LoadingOverlay isLoading={isLoading} />
<div className="h-full w-full overflow-x-scroll">
<div className={widthSize}>
<UiTable cellClick={(index: number | undefined) => index !== undefined && cellClick(index)} headName={"오수발생량 추정"} tableData={mainList} headlist={upheadList} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} />
<UiTable cellClick={(index: number | undefined) => index !== undefined && cellClick(index)} headName={"오수발생량 추정"} tableData={mainList} headlist={upheadList} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} widthFixed={true} />
</div>
</div>
</ListDiv>
@@ -1,9 +1,18 @@
"use client"
/**
* 운영실태 - 지하수 유입량 추정(모달)
*
* - 선택한 시설의 월별 청천시 실제 하수유입량, 오수발생량으로 지하수 유입량을 보여주는 모달
* - 청천시 실제 하수유입량 - 오수발생량으로 지하수유입량을 추정한다.
*/
"use client"
import { roundNumber } from "@/app/components/common/DataForm";
import { useFoStore } from "@/app/store";
import type { UnderWaterInputModalProps } from "@/app/store/underWaterInput/types";
import { downloadExcel } from "@common/business_components";
import { DateMonthPicker, UITab, UiTable } from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
import { Table, TableCell, TableHead, TableRow, TabsContent } from "@common/components/ui";
import { Button, Table, TableCell, TableHead, TableRow, TabsContent } from "@common/components/ui";
import { useEffect, useState } from "react";
type ModalProps ={
@@ -20,8 +29,8 @@ const tabList1 = [
export default function UnderWaterInputModal({fcltyCd='', fcltyName='',searchYear=new Date().getFullYear().toString()} : ModalProps) {
// 그리드 관련
const {UnderWaterDetail, unserWaterModal} = useFoStore((state) => state);
const {Common, UnderWaterDetail, unserWaterModal} = useFoStore((state) => state);
const { btnClass } = Common;
const [startYmDate, setStartYmDate] = useState<string>(searchYear+'01');
const [endYmDate, setEndYmDate] = useState<string>(searchYear+'12');
const [tabTerm, setTabTerm] = useState<string>('tab_term_year');
@@ -87,9 +96,31 @@ export default function UnderWaterInputModal({fcltyCd='', fcltyName='',searchYea
unserWaterModal(fcltyCd, searchYear, prevStartYmDate, prevEndYmDate);
} , [fcltyCd, searchYear, unserWaterModal, prevStartYmDate, prevEndYmDate]);
const excelDownload = () => {
const excelDownList: any[] = [];
if(copyYearList.length > 0){
copyYearList.forEach((item) => {
excelDownList.push({
"날짜": item.msrDt,
"청천시 실제 하수유입량(m³/일)": roundNumber(item.realSewageInput, 0),
"오수발생량(m³/일)": roundNumber(item.sewageOccur, 0),
"지하수 유입량(m³/일)": roundNumber(item.underWaterInput, 0),
});
});
}
if (excelDownList && excelDownList.length > 0) {
downloadExcel({ data: JSON.parse(JSON.stringify(excelDownList)), fileName: searchYear+'년 '+fcltyName + ' 지하수유입량', sheetNameArray: [fcltyName + ' 지하수유입량'], headerRange: 'A1:D1' });
} else if (copyYearList.length == 0) {
alert('다운받을 데이터가 없습니다.');
}
}
return (
<>
<UITab tabList={tabList1} defaultValue="tab_term_year" onValueChange={(val) => {setTabTerm(val)}}>
<Button className={btnClass} style={{float: 'right'}} color="green" onClick={excelDownload}>
{"엑셀다운로드"}
</Button>
<TabsContent value="tab_term_year">
<ListDiv className="!h-[100px]">
<div className="card !m-[1.2rem] max-h-[40rem] overflow-auto !p-0r">
@@ -142,6 +173,7 @@ export default function UnderWaterInputModal({fcltyCd='', fcltyName='',searchYea
onPageChange={() => {}}
className="h-[200px]"
boldArray={[0,1,2]}
widthFixed={true}
/>
</div>
</TabsContent>
@@ -209,6 +241,7 @@ export default function UnderWaterInputModal({fcltyCd='', fcltyName='',searchYea
onPageChange={() => { } }
className="h-[500px]"
boldArray={[0,1,2]}
widthFixed={true}
/>
</div>
</TabsContent>
@@ -267,6 +300,7 @@ export default function UnderWaterInputModal({fcltyCd='', fcltyName='',searchYea
onPageChange={() => {}}
className="h-[500px]"
boldArray={[0,1,2]}
widthFixed={true}
/>
</div>
</TabsContent>
@@ -1,4 +1,12 @@
"use client"
/**
* 운영실태 - 지하수 유입량 추정(메인)
*
* - 조회조건대로 시설별 연간, 하절기, 동절기 단위로 지하수 유입량 추정을 표로 보여주는 화면
* - 청천시 실제 하수유입량 - 오수발생량으로 지하수유입량을 추정한다.
* - 연간 지하수 유입량이 하수유입량보다 20% 클 경우 초과유입으로 아닌 경우 적정으로 적정여부를 표시한다.
*/
"use client"
import { useFoStore } from "@/app/store";
import type { TableUpperProps } from "@/app/store/common";
import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components";
@@ -220,9 +228,10 @@ export default function UnderWaterInput() {
<LoadingOverlay isLoading={isLoading} />
<div className="h-full w-full overflow-x-scroll">
<div className={widthSize}>
<UiTable cellClick={(index: number | undefined) => index !== undefined && cellClick(index)} headName={"지하수유입량 추정"} tableData={mainList} headlist={upheadList} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} />
<UiTable cellClick={(index: number | undefined) => index !== undefined && cellClick(index)} headName={"지하수유입량 추정"} tableData={mainList} headlist={upheadList} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} widthFixed={true}/>
</div>
</div>
<span className="text-2xl text-gray-500">※적정여부 = 연간 지하수유입량/연평균 유입하수량*100 </span><br></br>
<span className="text-2xl text-gray-500">※지하수 유입량 = 하수처리장 청천시 실제유입량 - (물사용량 × 오수전환율)</span>
</ListDiv>
</ContentsDiv>
+19 -1
View File
@@ -201,6 +201,9 @@ const selectMiddleRegionData: SelectDataType[] = [
{ text: "전체", val: '0' }
];
// 오수전환율
export const OSU_PERCENT = 0.9;
/**
* 반올림 함수
* @param value : 대상 숫자
@@ -211,6 +214,19 @@ export const roundUp = (value: number, precision: number = 1): number => {
return Math.round(value * (10 ** precision)) / (10 ** precision);
}
/**
* 수질 데이터 포맷 변경 함수
* @param value : 수질 데이터
* @param day : 일수
* @param digit : 소수점 자리수
*/
export const qltyDataSetting = (value: number, day : number, digit: number) => {
const toZero = digit === 1 ? '0.0' : digit === 2 ? '0.00' : '0.000';
return value > 0 ? roundUp((value/day), digit).toFixed(digit) : toZero;
};
export const COD_YEAR = 2021;
/**
* STORE - API
*/
@@ -378,6 +394,7 @@ export type CommonType = {
selectFlowPanel: SelectDataType[];
selectEnvPartData: envPartSelectDataType[];
btnClass: string;
COD_YEAR : number;
};
auth: {
@@ -406,7 +423,8 @@ export const commonState: CommonType = {
selectFlowTerm: selectFlowTerm,
selectFlowPanel: selectFlowPanel,
selectEnvPartData: selectEnvPartData,
btnClass: "p-4 m-2 text-white rounded-sm text-lg font-medium",
btnClass: "p-4 m-2 !mr-10 text-white rounded-sm text-lg font-medium",
COD_YEAR : COD_YEAR,
},
auth: {
File diff suppressed because it is too large Load Diff
@@ -1,6 +1,7 @@
import DataForm from "@/app/components/common/DataForm";
import type { TableUpperProps } from "../dashboard";
import { getFetch } from "@/app/components/api";
import CalcRainEffect from "@/app/components/common/CalcRainEffect";
import { roundNumber } from "@/app/components/common/DataForm";
import type { TableUpperProps } from "../dashboard";
export type { TableUpperProps };
/**====================================
* Store - 타입
@@ -49,11 +50,11 @@ export interface ExcelType {
시군구: string,
시설이름: string,
주소: string,
시설용량: number,
"시설옹량(m³/일)": number,
관측소정보 : string,
강우일 : number,
강우영향일 : number,
연간총강수량 : number,
"강우일(일)": number,
"강우영향일(일)": number,
"연간총강수량(mm)": number,
}
/**====================================
@@ -68,48 +69,48 @@ const LabelArray:string[] = ['구분', '시도', '시군구','용량별', '시
// 리스트 헤더
const upHeadList1:TableUpperProps[] = [
{ id: "A", title: "행정구역", row: 0, colSpan: 2 },
{ id: "sido", title: "시도", upName:"upChangeRe", upSequnce:1, row: 1 },
{ id: "gugun", title: "시군구", upName:"upChangeRe",upSequnce:2, row: 1 },
{ id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2},
{ id: "A", title: "행정구역", row: 0, colSpan: 2, widthPercent: 20 },
{ id: "sido", title: "시도", upName:"upChangeRe", upSequnce:1, row: 1, widthPercent: 10 },
{ id: "gugun", title: "시군구", upName:"upChangeRe",upSequnce:2, row: 1, widthPercent: 10 },
{ id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2, widthPercent: 10},
{ id: "addr", title: "주소", row: 0, rowSpan: 2},
{ id: "fctCpc", title: "시설용량(m³/일)", row: 0, rowSpan: 2, align:"right"},
{ id: "stnKo", title: "관측소 정보", row: 0, rowSpan: 2},
{ id: "infoRnDay", title: "강우일\n(일)", row: 0, rowSpan: 2, align:"right"},
{ id: "rainEffectDay", title: "강우영향일\n(일)", row: 0, rowSpan: 2, align:"right"},
{ id: "totalYearRain", title: "연간 총 총강수량\n(mm)", row: 0, rowSpan: 2, align:"right"}
{ id: "fctCpc", title: "시설용량(m³/일)", row: 0, rowSpan: 2, align:"right", widthPercent: 10 },
{ id: "stnKo", title: "관측소 정보", row: 0, rowSpan: 2, widthPercent: 10 },
{ id: "infoRnDay", title: "강우일\n(일)", row: 0, rowSpan: 2, align:"right", widthPercent: 7 },
{ id: "rainEffectDay", title: "강우영향일\n(일)", row: 0, rowSpan: 2, align:"right", widthPercent: 7 },
{ id: "totalYearRain", title: "연간 총 총강수량\n(mm)", row: 0, rowSpan: 2, align:"right", widthPercent: 7 }
];
const upHeadList2:TableUpperProps[] = [
{ id: "A", title: "유역", row: 0, colSpan: 3} ,
{ id: "rvbsn", title: "권역", upName:"upChangeRe", upSequnce:1, row: 1} ,
{ id: "lgbsn", title: "단위유역", upName:"upChangeRe", upSequnce:2, row: 1},
{ id: "mdmbsn", title: "중권역", upName:"upChangeRe", upSequnce:3, row: 1},
{ id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2},
{ id: "A", title: "유역", row: 0, colSpan: 3, widthPercent: 21 } ,
{ id: "rvbsn", title: "권역", upName:"upChangeRe", upSequnce:1, row: 1, widthPercent: 7 } ,
{ id: "lgbsn", title: "단위유역", upName:"upChangeRe", upSequnce:2, row: 1, widthPercent: 7 },
{ id: "mdmbsn", title: "중권역", upName:"upChangeRe", upSequnce:3, row: 1, widthPercent: 7 },
{ id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2, widthPercent: 10 },
{ id: "addr", title: "주소", row: 0, rowSpan: 2},
{ id: "fctCpc", title: "시설용량(m³/일)", row: 0, rowSpan: 2, align:"right"},
{ id: "stnKo", title: "관측소 정보", row: 0, rowSpan: 2},
{ id: "infoRnDay", title: "강우일\n(일)", row: 0, rowSpan: 2, align:"right"},
{ id: "rainEffectDay", title: "강우영향일\n(일)", row: 0, rowSpan: 2, align:"right"},
{ id: "totalYearRain", title: "연간 총 총강수량\n(mm)", row: 0, rowSpan: 2, align:"right"}
{ id: "fctCpc", title: "시설용량(m³/일)", row: 0, rowSpan: 2, align:"right", widthPercent: 10 },
{ id: "stnKo", title: "관측소 정보", row: 0, rowSpan: 2, widthPercent: 10 },
{ id: "infoRnDay", title: "강우일\n(일)", row: 0, rowSpan: 2, align:"right", widthPercent: 7 },
{ id: "rainEffectDay", title: "강우영향일\n(일)", row: 0, rowSpan: 2, align:"right", widthPercent: 7 },
{ id: "totalYearRain", title: "연간 총 총강수량\n(mm)", row: 0, rowSpan: 2, align:"right", widthPercent: 7 }
];
const upHeadList3:TableUpperProps[] = [
{ id: "A", title: "유역", row: 0, colSpan: 3} ,
{ id: "rvbsn", title: "권역", upName:"upChangeRe1", upSequnce:1, row: 1},
{ id: "lgbsn", title: "단위유역", upName:"upChangeRe1", upSequnce:2, row: 1},
{ id: "mdmbsn", title: "중권역", upName:"upChangeRe1", upSequnce:3, row: 1},
{ id: "rgnNm", title: "환경청", row: 0, rowSpan: 2},
{ id: "B", title: "행정구역", upName:"upChangeRe2", row: 0, colSpan: 2},
{ id: "sido", title: "시도", upName:"upChangeRe2", upSequnce:1, row: 1},
{ id: "gugun", title: "시군구", upName:"upChangeRe2",upSequnce:2, row: 1},
{ id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2},
{ id: "A", title: "유역", row: 0, colSpan: 3, widthPercent: 15 } ,
{ id: "rvbsn", title: "권역", upName:"upChangeRe1", upSequnce:1, row: 1, widthPercent: 5 },
{ id: "lgbsn", title: "단위유역", upName:"upChangeRe1", upSequnce:2, row: 1, widthPercent: 5 },
{ id: "mdmbsn", title: "중권역", upName:"upChangeRe1", upSequnce:3, row: 1, widthPercent: 5 },
{ id: "rgnNm", title: "환경청", row: 0, rowSpan: 2, widthPercent: 7 },
{ id: "B", title: "행정구역", upName:"upChangeRe2", row: 0, colSpan: 2, widthPercent: 10 },
{ id: "sido", title: "시도", upName:"upChangeRe2", upSequnce:1, row: 1, widthPercent: 5 },
{ id: "gugun", title: "시군구", upName:"upChangeRe2",upSequnce:2, row: 1, widthPercent: 5 },
{ id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2, widthPercent: 10 },
{ id: "addr", title: "주소", row: 0, rowSpan: 2},
{ id: "fctCpc", title: "시설용량(m³/일)", row: 0, rowSpan: 2, align:"right"},
{ id: "stnKo", title: "관측소 정보", row: 0, rowSpan: 2},
{ id: "infoRnDay", title: "강우일\n(일)", row: 0, rowSpan: 2, align:"right"},
{ id: "rainEffectDay", title: "강우영향일\n(일)", row: 0, rowSpan: 2, align:"right"},
{ id: "totalYearRain", title: "연간 총 총강수량\n(mm)", row: 0, rowSpan: 2, align:"right"}
{ id: "fctCpc", title: "시설용량(m³/일)", row: 0, rowSpan: 2, align:"right", widthPercent: 10 },
{ id: "stnKo", title: "관측소 정보", row: 0, rowSpan: 2, widthPercent: 10 },
{ id: "infoRnDay", title: "강우일\n(일)", row: 0, rowSpan: 2, align:"right", widthPercent: 7 },
{ id: "rainEffectDay", title: "강우영향일\n(일)", row: 0, rowSpan: 2, align:"right", widthPercent: 7 },
{ id: "totalYearRain", title: "연간 총 총강수량\n(mm)", row: 0, rowSpan: 2, align:"right", widthPercent: 7 }
];
const facilityPrecipitation:FacilityPrecipitationProps[] = [
@@ -135,7 +136,6 @@ const gridListPrecipitationDetail:PrecipitationPropsDetailProps[] = [
const fetchFacilityPrecipitationList = async (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => {
const tailStr = '/'+pageNo + '/' + pageSize + '/' + searchYear + (part?'/' + part:'' ) + (nameCd?'/' + nameCd:'' ) + (fcltCpct?'/' + fcltCpct:'' ) + (operationValue?'/' + operationValue:'' ) + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') ;
console.log('tailStr', tailStr);
const url = '/fclt/rain' + tailStr;
const res = await getFetch('fo', url);
const tmpData:PrecipitationPropsDetailProps[] = [];
@@ -146,45 +146,30 @@ const fetchFacilityPrecipitationList = async (pageNo: number, pageSize: number,
const rainDt = res.data[idx].rainyDayObjList[idx2].rainDt;
const infoRnDay = res.data[idx].rainyDayObjList[idx2].infoRnDay;
const rainDay = res.data[idx].rainyDayObjList[idx2].infoRnDay>=3?1:0;
let rainEffectDay = 0;
if(idx2 < res.data[idx].rainyDayObjList.length-2){
if(rainDay==1){
rainEffectDay = 1;
} else {
if(idx2 >= 2){
if(res.data[idx].rainyDayObjList[idx2-1].infoRnDay>=3 || res.data[idx].rainyDayObjList[idx2-2].infoRnDay>=3){
rainEffectDay = 1;
}
}
}
} else if(idx2 < res.data[idx].rainyDayObjList.length-1){
if(rainDay==1 || res.data[idx].rainyDayObjList[idx2+1].infoRnDay>=3){
rainEffectDay = 1;
}
} else {
rainEffectDay = rainDay;
}
tmpData.push({
bscFctCd : bscFctCd,
rainDt : rainDt,
infoRnDay : infoRnDay,
rainDay : rainDay,
rainEffectDay : rainEffectDay
rainEffectDay : rainDay
})
}
}
res.data.map((item: FacilityPrecipitationProps) => {
const filteredList = tmpData.filter((gridItem) => {
return gridItem.bscFctCd === item.bscFctCd;
return gridItem.bscFctCd === item.bscFctCd;
});
item.rainEffectDay = filteredList.reduce((acc, curr) => acc + curr.rainEffectDay, 0);
item.totalYearRain = filteredList.reduce((acc, curr) => acc + curr.infoRnDay, 0);
const rtnData = CalcRainEffect(filteredList);
item.rainEffectDay = rtnData.reduce((acc, curr) => acc + curr.rainEffectDay, 0);
item.totalYearRain = rtnData.reduce((acc, curr) => acc + Number(curr.infoRnDay), 0);
item.infoRnDay = filteredList.reduce((acc, curr) => acc + curr.rainDay, 0);
})
});
}
return { data: res.data, count: res.count, detailData: tmpData };
}
@@ -195,11 +180,6 @@ export type FacilityPrecipitationActions = {
searchFacilityPrecipitationList: (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => void;
}
const dataFormSetting=(item : FacilityPrecipitationProps)=> {
DataForm({ type: 'number', column: 'fctCpc', item: item as unknown as Record<string, unknown> });
DataForm({ type: 'float1', column: 'totalYearRain', item: item as unknown as Record<string, unknown>});
};
export type FacilityPrecipitationType = {
FacilityPrecipitationSearch: {
isInit: boolean;
@@ -263,13 +243,16 @@ export const facilityPrecipitationReducer:(set:(fn: (state: FacilityPrecipitatio
const res = await fetchFacilityPrecipitationList(pageNo, pageSize, searchYear, part, nameCd, fcltCpct, operationValue, fcltyNm);
const data = res.data;
data.forEach(item => {
item.fctCpc = roundNumber(item.fctCpc, 0);
item.totalYearRain = roundNumber(item.totalYearRain, 1);
});
const excelDownList: ExcelType[] = [];
if(pageSize>5000){
data.forEach((item: FacilityPrecipitationProps) => {
dataFormSetting(item)
item.fctCpc = item.fctCpc ? parseFloat(item.fctCpc.toString().replace(/,/g, '')) : 0;
item.totalYearRain = item.totalYearRain ? parseFloat(item.totalYearRain.toString().replace(/,/g, '')) : 0;
excelDownList.push({
시설코드: item.bscFctCd,
권역: item.rvbsn,
@@ -280,25 +263,19 @@ export const facilityPrecipitationReducer:(set:(fn: (state: FacilityPrecipitatio
시군구: item.gugun,
시설이름: item.bscFctNm,
주소: item.addr,
시설용량: item.fctCpc,
"시설옹량(m³/일)": item.fctCpc,
관측소정보: item.stnKo,
강우일: item.infoRnDay,
강우영향일: item.rainEffectDay,
연간총강수량: item.totalYearRain,
"강우일(일)": item.infoRnDay,
"강우영향일(일)": item.rainEffectDay,
"연간총강수량(mm)": item.totalYearRain,
})
})
}else{
data.forEach((item: FacilityPrecipitationProps) => {
dataFormSetting(item)
item.fctCpc = item.fctCpc ? parseFloat(item.fctCpc.toString().replace(/,/g, '')) : 0;
item.totalYearRain = item.totalYearRain ? parseFloat(item.totalYearRain.toString().replace(/,/g, '')) : 0;
})
}
set((state:FacilityPrecipitationType) => ({
...state,
FacilityPrecipitation: pageSize<5000?{
...state.FacilityPrecipitation,
facilityPrecipitation: res.data,
facilityPrecipitation: data,
facilityPrecipitationCount: res.count,
isLoading : false,
}:{
+158 -136
View File
@@ -1,6 +1,9 @@
import { getFetch } from "@/app/components/api";
import DataForm from "@/app/components/common/DataForm";
import DataForm, { roundNumber } from "@/app/components/common/DataForm";
import type { TableUpperProps } from "../dashboard";
import CalcRainEffect from "@/app/components/common/CalcRainEffect";
import { COD_YEAR } from "../common";
import CommaToNumber from "@/app/components/common/CommaToNumber";
export type { TableUpperProps };
/**====================================
@@ -25,6 +28,8 @@ export interface FacilityWaterQltyProps {
inflAssctAftWqltBod: string | '',
inflAssctBfrWqltToc: string | '',
inflAssctAftWqltToc: string | '',
inflAssctBfrWqltCod : string | '',
inflAssctAftWqltCod : string | '',
inflAssctBfrWqltSs: string | '',
inflAssctAftWqltSs: string | '',
inflAssctBfrWqltTn: string | '',
@@ -33,6 +38,7 @@ export interface FacilityWaterQltyProps {
inflAssctAftWqltTp: string | '',
efflWqltBod: string | '',
efflWqltToc: string | '',
efflWqltCod : string | '',
efflWqltSs: string | '',
efflWqltTn: string | '',
efflWqltTp: string | '',
@@ -42,7 +48,7 @@ export interface FacilityWaterQltyProps {
mdmbsn:string|'',
inflAmnt: number | '',
lclgvrnmntNm: string,
infoRnDay: number | '',
infoRnDay: number | string | '',
rainEffectDay: number | '',
tpInflWqltTmprtr: number | '',
tpInflWqltPh: string | '',
@@ -53,6 +59,7 @@ export interface FacilityWaterQltyProps {
tpInflWqltTp: string | '',
tpInflWqltEclgyTox: string | '',
tpInflWqltClfgrpcnt: string | '',
noProcessInflAmnt : string | number | '',
}
export interface ExcelType {
시설코드: string,
@@ -64,17 +71,17 @@ export interface ExcelType {
시군구: string,
시설이름: string,
주소: string,
용량: number,
유입BOD: string | '',
유입TOC: string | '',
유입SS: string | '',
유입TN: string | '',
유입TP: string | '',
유출BOD: string | '',
유출TOC: string | '',
유출SS: string | '',
유출TN: string | '',
유출TP: string | '',
"시설용량(m³/일)": number | '',
"유입BOD(mg/L)": number | '',
"유입TOC(mg/L)": number | '',
"유입SS(mg/L)": number | '',
"유입TN(mg/L)": number | '',
"유입TP(mg/L)": number | '',
"유출BOD(mg/L)": number | '',
"유출TOC(mg/L)": number | '',
"유출SS(mg/L)": number | '',
"유출TN(mg/L)": number | '',
"유출TP(mg/L)": number | '',
}
/**
@@ -98,17 +105,17 @@ export interface WaterQualityHistoryResponse {
export type modalExcelType = {
날짜: string;
"유입BOD(mg/L)": string;
"유입TOC(COD)(mg/L)": string;
"유입SS(mg/L)": string;
"유입TN(mg/L)": string;
"유입TP(mg/L)": string;
"유출BOD(mg/L)": string;
"유출TOC(COD)(mg/L)": string;
"유출SS(mg/L)": string;
"유출TN(mg/L)": string;
"유출TP(mg/L)": string;
/* "강우량(mm/일)": string; */
"유입BOD(mg/L)": number | '';
"유입TOC(COD)(mg/L)": number | '';
"유입SS(mg/L)": number | '';
"유입TN(mg/L)": number | '';
"유입TP(mg/L)": number | '';
"유출BOD(mg/L)": number | '';
"유출TOC(COD)(mg/L)": number | '';
"유출SS(mg/L)": number | '';
"유출TN(mg/L)": number | '';
"유출TP(mg/L)": number | '';
"강우량(mm/일)": number | '';
}
/**====================================
@@ -122,74 +129,74 @@ const mainLabelArray: string[] = ['구분', '시도', '시군구', '용량별',
// 시설수질리스트 헤더(행정별)
const upHeadList1: TableUpperProps[] = [
{ id: "C", title: "행정명", colSpan: 2, row: 0 },
{ id: "sidoNm", title: "시도", row: 1 },
{ id: "sggNm", title: "시군구", row: 1 },
{ id: "bscFctNm", title: "시설명", rowSpan: 2, row: 0 },
{ id: "C", title: "행정명", colSpan: 2, row:0, widthPercent:10 },
{ id: "sidoNm", title: "시도", row: 1, widthPercent:5},
{ id: "sggNm", title: "시군구", row: 1, widthPercent:5 },
{ id: "bscFctNm", title: "시설명", rowSpan: 2, row: 0, widthPercent: 10 },
{ id: "addr", title: "주소", rowSpan: 2, row: 0 },
{ id: "fctCpc", title: "시설용량(m³/일)", align: "right", rowSpan: 2, row: 0 },
{ id: "A", title: "유입", colSpan: 5, row: 0 },
{ id: "B", title: "방류", colSpan: 5, row: 0 },
{ id: "inflAssctBfrWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe3", upSequnce: 1, align: "right", row: 1 },
{ id: "inflAssctBfrWqltToc", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe3", upSequnce: 2, align: "right", row: 1 },
{ id: "inflAssctBfrWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row: 1 },
{ id: "inflAssctBfrWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe3", upSequnce: 4, align: "right", row: 1 },
{ id: "inflAssctBfrWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row: 1 },
{ id: "efflWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe4", upSequnce: 1, align: "right", row: 1 },
{ id: "efflWqltToc", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe4", upSequnce: 2, align: "right", row: 1 },
{ id: "efflWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row: 1 },
{ id: "efflWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe4", upSequnce: 4, align: "right", row: 1 },
{ id: "efflWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row: 1 },
{ id: "fctCpc", title: "시설용량(m³/일)", align: "right", rowSpan: 2, row: 0, widthPercent:10 },
{ id: "A", title: "유입", colSpan: 5, row: 0, widthPercent:25 },
{ id: "B", title: "방류", colSpan: 5, row: 0, widthPercent:25 },
{ id: "inflAssctBfrWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe3", upSequnce: 1, align: "right", row: 1, widthPercent:5 },
{ id: "inflAssctBfrWqltToc", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe3", upSequnce: 2, align: "right", row: 1, widthPercent:5 },
{ id: "inflAssctBfrWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row: 1, widthPercent:5 },
{ id: "inflAssctBfrWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe3", upSequnce: 4, align: "right", row: 1, widthPercent:5 },
{ id: "inflAssctBfrWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row: 1, widthPercent:5 },
{ id: "efflWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe4", upSequnce: 1, align: "right", row: 1, widthPercent:5 },
{ id: "efflWqltToc", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe4", upSequnce: 2, align: "right", row: 1, widthPercent:5 },
{ id: "efflWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row: 1, widthPercent:5 },
{ id: "efflWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe4", upSequnce: 4, align: "right", row: 1, widthPercent:5 },
{ id: "efflWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row: 1, widthPercent:5 },
];
// 시설수질리스트 헤더(권역별)
const upHeadList2: TableUpperProps[] = [
{ id: "C", title: "유역", colSpan: 3, row: 0 },
{ id: "rvbsn", title: "권역", upName: "upChangeRe1", upSequnce: 1, row:1 },
{ id: "lgbsn", title: "단위유역", upName: "upChangeRe1", upSequnce: 2, row:1 },
{ id: "mdmbsn", title: "중권역", upName: "upChangeRe1", upSequnce: 3, row:1 },
{ id: "bscFctNm", title: "시설명", row:0, rowSpan:2 },
{ id: "C", title: "유역", colSpan: 3, row: 0, widthPercent:15 },
{ id: "rvbsn", title: "권역", upName: "upChangeRe1", upSequnce: 1, row:1, widthPercent:5 },
{ id: "lgbsn", title: "단위유역", upName: "upChangeRe1", upSequnce: 2, row:1, widthPercent:5 },
{ id: "mdmbsn", title: "중권역", upName: "upChangeRe1", upSequnce: 3, row:1, widthPercent:5 },
{ id: "bscFctNm", title: "시설명", row:0, rowSpan:2, widthPercent:10 },
{ id: "addr", title: "주소", row:0, rowSpan:2 },
{ id: "fctCpc", title: "시설용량(m³/L)", align: "right", row:0, rowSpan:2 },
{ id: "A", title: "유입", colSpan: 5, row: 0 },
{ id: "B", title: "방류", colSpan: 5, row: 0 },
{ id: "inflAssctBfrWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe3", upSequnce: 1, align: "right", row:1 },
{ id: "inflAssctBfrWqltToc", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe3", upSequnce: 2, align: "right", row:1 },
{ id: "inflAssctBfrWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row:1 },
{ id: "inflAssctBfrWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe3", upSequnce: 2, align: "right", row:1 },
{ id: "inflAssctBfrWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row:1 },
{ id: "efflWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe4", upSequnce: 1, align: "right", row:1 },
{ id: "efflWqltToc", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe4", upSequnce: 2, align: "right", row:1 },
{ id: "efflWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row:1 },
{ id: "efflWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe4", upSequnce: 2, align: "right", row:1 },
{ id: "efflWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row:1 },
{ id: "fctCpc", title: "시설용량(m³/L)", align: "right", row:0, rowSpan:2, widthPercent:8 },
{ id: "A", title: "유입", colSpan: 5, row: 0, widthPercent:25 },
{ id: "B", title: "방류", colSpan: 5, row: 0, widthPercent:25 },
{ id: "inflAssctBfrWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe3", upSequnce: 1, align: "right", row:1, widthPercent:5 },
{ id: "inflAssctBfrWqltToc", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe3", upSequnce: 2, align: "right", row:1, widthPercent:5 },
{ id: "inflAssctBfrWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row:1, widthPercent:5 },
{ id: "inflAssctBfrWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe3", upSequnce: 2, align: "right", row:1, widthPercent:5 },
{ id: "inflAssctBfrWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row:1, widthPercent:5 },
{ id: "efflWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe4", upSequnce: 1, align: "right", row:1, widthPercent:5 },
{ id: "efflWqltToc", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe4", upSequnce: 2, align: "right", row:1, widthPercent:5 },
{ id: "efflWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row:1, widthPercent:5 },
{ id: "efflWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe4", upSequnce: 2, align: "right", row:1, widthPercent:5 },
{ id: "efflWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row:1, widthPercent:5 },
];
// 시설수질리스트 헤더(환경청별)
const upHeadList3: TableUpperProps[] = [
{ id: "C", title: "유역", colSpan: 3, row: 0 },
{ id: "rvbsn", title: "권역", row:1 },
{ id: "lgbsn", title: "단위유역", row:1 },
{ id: "mdmbsn", title: "중권역", row:1 },
{ id: "rgnNm", title: "환경청", row:0, rowSpan:2 },
{ id: "D", title: "행정명", colSpan: 2, row: 0 },
{ id: "sidoNm", title: "시도", upName: "upChangeRe2", row:1 },
{ id: "sggNm", title: "시군구", upName: "upChangeRe2", row:1 },
{ id: "bscFctNm", title: "시설명", row:0, rowSpan:2 },
{ id: "C", title: "유역", colSpan: 3, row: 0, widthPercent: 15 },
{ id: "rvbsn", title: "권역", row:1, widthPercent: 5 },
{ id: "lgbsn", title: "단위유역", row:1, widthPercent: 5 },
{ id: "mdmbsn", title: "중권역", row:1, widthPercent: 5 },
{ id: "rgnNm", title: "환경청", row:0, rowSpan:2, widthPercent: 7 },
{ id: "D", title: "행정명", colSpan: 2, row: 0, widthPercent: 10 },
{ id: "sidoNm", title: "시도", upName: "upChangeRe2", row:1, widthPercent: 5 },
{ id: "sggNm", title: "시군구", upName: "upChangeRe2", row:1, widthPercent: 5 },
{ id: "bscFctNm", title: "시설명", row:0, rowSpan:2, widthPercent: 8 },
{ id: "addr", title: "주소", row:0, rowSpan:2 },
{ id: "fctCpc", title: "시설용량(m³/L)", align: "right", row:0, rowSpan:2 },
{ id: "A", title: "유입", colSpan: 5, row: 0 },
{ id: "B", title: "방류", colSpan: 5, row: 0 },
{ id: "inflAssctBfrWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe3", upSequnce: 1, align: "right", row:1 },
{ id: "inflAssctBfrWqltToc", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe3", upSequnce: 2, align: "right", row:1 },
{ id: "inflAssctBfrWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row:1 },
{ id: "inflAssctBfrWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe3", upSequnce: 2, align: "right", row:1 },
{ id: "inflAssctBfrWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row:1 },
{ id: "efflWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe4", upSequnce: 1, align: "right", row:1 },
{ id: "efflWqltToc", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe4", upSequnce: 2, align: "right", row:1 },
{ id: "efflWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row:1 },
{ id: "efflWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe4", upSequnce: 2, align: "right", row:1 },
{ id: "efflWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row:1 },
{ id: "fctCpc", title: "시설용량(m³/L)", align: "right", row:0, rowSpan:2, widthPercent: 5 },
{ id: "A", title: "유입", colSpan: 5, row: 0, widthPercent: 20 },
{ id: "B", title: "방류", colSpan: 5, row: 0, widthPercent: 20 },
{ id: "inflAssctBfrWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe3", upSequnce: 1, align: "right", row:1, widthPercent: 4 },
{ id: "inflAssctBfrWqltToc", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe3", upSequnce: 2, align: "right", row:1, widthPercent: 4 },
{ id: "inflAssctBfrWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row:1, widthPercent: 4 },
{ id: "inflAssctBfrWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe3", upSequnce: 2, align: "right", row:1, widthPercent: 4 },
{ id: "inflAssctBfrWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe3", upSequnce: 3, align: "right", row:1, widthPercent: 4 },
{ id: "efflWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe4", upSequnce: 1, align: "right", row:1, widthPercent: 4 },
{ id: "efflWqltToc", title: "TOC\n(COD)\n(mg/L)", upName: "upChangeRe4", upSequnce: 2, align: "right", row:1, widthPercent: 4 },
{ id: "efflWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row:1, widthPercent: 4 },
{ id: "efflWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe4", upSequnce: 2, align: "right", row:1, widthPercent: 4 },
{ id: "efflWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe4", upSequnce: 3, align: "right", row:1, widthPercent: 4 },
];
/**
@@ -208,7 +215,23 @@ const upHeadListModalYear: TableUpperProps[] = [
{ id: "efflWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe2", upSequnce: 3, align: "right" },
{ id: "efflWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe2", upSequnce: 2, align: "right" },
{ id: "efflWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe2", upSequnce: 3, align: "right" },
/* { id: "infoRnDay", title: "강우량(mm/일)", align: "right" }, */
{ id: "infoRnDay", title: "강우량\n(mm/일)", align: "right" }
];
// 처리시설 수질현황 헤더(모달-연간)
const upHeadListModalYearCod: TableUpperProps[] = [
{ id: "msrDt", title: "날짜" },
{ id: "inflAssctBfrWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe1", upSequnce: 1, align: "right" },
{ id: "inflAssctBfrWqltCod", title: "TOC(COD)\n(mg/L)", upName: "upChangeRe1", upSequnce: 2, align: "right" },
{ id: "inflAssctBfrWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe1", upSequnce: 3, align: "right" },
{ id: "inflAssctBfrWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe1", upSequnce: 2, align: "right" },
{ id: "inflAssctBfrWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe1", upSequnce: 3, align: "right" },
{ id: "efflWqltBod", title: "BOD\n(mg/L)", upName: "upChangeRe2", upSequnce: 1, align: "right" },
{ id: "efflWqltCod", title: "TOC(COD)\n(mg/L)", upName: "upChangeRe2", upSequnce: 2, align: "right" },
{ id: "efflWqltSs", title: "SS\n(mg/L)", upName: "upChangeRe2", upSequnce: 3, align: "right" },
{ id: "efflWqltTn", title: "T-N\n(mg/L)", upName: "upChangeRe2", upSequnce: 2, align: "right" },
{ id: "efflWqltTp", title: "T-P\n(mg/L)", upName: "upChangeRe2", upSequnce: 3, align: "right" },
{ id: "infoRnDay", title: "강우량\n(mm/일)", align: "right" }
];
// 처리시설 수질현황 헤더(모달-수질TMS)
@@ -295,6 +318,7 @@ export type FacilityWaterQltyType = {
FacilityWaterQltyModal: {
// 처리시설 수질현황
upHeadListModalYear: TableUpperProps[];
upHeadListModalYearCod : TableUpperProps[];
facilityWaterQltyYearList: FacilityWaterQltyProps[];
upHeadListModalTms: TableUpperProps[];
facilityWaterQltyTmsList: FacilityWaterQltyTmsProps[];
@@ -324,6 +348,7 @@ export const facilityWaterQltyInitState: FacilityWaterQltyType = {
FacilityWaterQltyModal: {
// 처리시설 수질현황
upHeadListModalYear: upHeadListModalYear,
upHeadListModalYearCod: upHeadListModalYearCod,
facilityWaterQltyYearList: facilityWaterQltyYearList,
upHeadListModalTms: upHeadListModalTms,
facilityWaterQltyTmsList: facilityWaterQltyTmsList,
@@ -375,6 +400,7 @@ export type FacilityWaterQltyActions = {
*/
const dataFormSetting = (item: FacilityWaterQltyProps) => {
DataForm({ type: 'date', column: 'msrDt', item: item as unknown as Record<string, unknown> });
DataForm({ type: 'float1', column: 'infoRnDay', item: item as unknown as Record<string, unknown> });
}
export type FacilityWaterQltyStore = FacilityWaterQltyType & FacilityWaterQltyActions;
@@ -449,8 +475,8 @@ export const facilityWaterQltyReducer = (set: (fn: (state: FacilityWaterQltyType
item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, ''));
item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || '';
item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || '';
item.inflAssctBfrWqltToc = Number(searchYear)<2021? "("+item.inflAssctBfrWqltToc+")" : item.inflAssctBfrWqltToc;
item.efflWqltToc = Number(searchYear)<2021? "("+item.efflWqltToc+")" : item.efflWqltToc;
item.inflAssctBfrWqltToc = Number(searchYear)<COD_YEAR? "("+item.inflAssctBfrWqltToc+")" : item.inflAssctBfrWqltToc;
item.efflWqltToc = Number(searchYear)<COD_YEAR? "("+item.efflWqltToc+")" : item.efflWqltToc;
excelDownList.push({
시설코드: item.bscFctCd,
권역: item.rvbsn,
@@ -461,17 +487,17 @@ export const facilityWaterQltyReducer = (set: (fn: (state: FacilityWaterQltyType
시군구: item.sggNm,
시설이름: item.bscFctNm,
주소: item.addr,
용량: item.fctCpc,
유입BOD: item.inflAssctBfrWqltBod,
유입TOC: item.inflAssctBfrWqltToc,
유입SS: item.inflAssctBfrWqltSs,
유입TN: item.inflAssctBfrWqltTn,
유입TP: item.inflAssctBfrWqltTp,
유출BOD: item.efflWqltBod,
유출TOC: item.efflWqltToc,
유출SS: item.efflWqltSs,
유출TN: item.efflWqltTn,
유출TP: item.efflWqltTp,
"시설용량(m³/일)": CommaToNumber(item.fctCpc),
"유입BOD(mg/L)": CommaToNumber(item.inflAssctBfrWqltBod),
"유입TOC(mg/L)": CommaToNumber(item.inflAssctBfrWqltToc),
"유입SS(mg/L)": CommaToNumber(item.inflAssctBfrWqltSs),
"유입TN(mg/L)": CommaToNumber(item.inflAssctBfrWqltTn),
"유입TP(mg/L)": CommaToNumber(item.inflAssctBfrWqltTp),
"유출BOD(mg/L)": CommaToNumber(item.efflWqltBod),
"유출TOC(mg/L)": CommaToNumber(item.efflWqltToc),
"유출SS(mg/L)": CommaToNumber(item.efflWqltSs),
"유출TN(mg/L)": CommaToNumber(item.efflWqltTn),
"유출TP(mg/L)": CommaToNumber(item.efflWqltTp),
});
});
}else{
@@ -480,8 +506,8 @@ export const facilityWaterQltyReducer = (set: (fn: (state: FacilityWaterQltyType
item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, ''));
item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || '';
item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || '';
item.inflAssctBfrWqltToc = Number(searchYear)<2021? "("+item.inflAssctBfrWqltToc+")" : item.inflAssctBfrWqltToc;
item.efflWqltToc = Number(searchYear)<2021? "("+item.efflWqltToc+")" : item.efflWqltToc;
item.inflAssctBfrWqltToc = Number(searchYear)<COD_YEAR? "("+item.inflAssctBfrWqltToc+")" : item.inflAssctBfrWqltToc;
item.efflWqltToc = Number(searchYear)<COD_YEAR? "("+item.efflWqltToc+")" : item.efflWqltToc;
});
}
set((state: FacilityWaterQltyType) => ({
@@ -573,48 +599,33 @@ export const facilityWaterQltyReducer = (set: (fn: (state: FacilityWaterQltyType
}
// facilityPrecipitation의 rainEffectDay 계산 로직을 적용
const data = res.data.wqltObjs;
// 강우영향일 계산 (강우량이 3 초과이면 무조건 강우영향일)
for(let idx = 0; idx < data.length; idx++) {
const item = data[idx];
if(item){
if(item.infoRnDay && Number(item.infoRnDay) > 3) {
item.rainEffectDay = 1;
} else {
item.rainEffectDay = 0;
}
}
}
const data = CalcRainEffect(res.data.wqltObjs);
// 이틀 전, 하루 전이 강우영향일(3 이상)인 경우 해당 날도 강우영향일로 설정
for(let idx = 0; idx < data.length; idx++) {
if(data[idx]) {
// 하루 전이 강우영향일(3 이상)인 경우
if(idx > 0 && data[idx-1]?.infoRnDay && Number(data[idx-1]?.infoRnDay) >= 3) {
data[idx]!.rainEffectDay = 1;
}
// 이틀 전이 강우영향일(3 이상)인 경우
if(idx > 1 && data[idx-2]?.infoRnDay && Number(data[idx-2]?.infoRnDay) >= 3) {
data[idx]!.rainEffectDay = 1;
}
}
}
/**
* [(강우시 일별유입유량*강우시 일별유입BOD)-(청천시 연평균유입유량*청천시 연평균유입BOD)]​
/강우시 일별유입BOD)
*/
//let rainInflAmnt = 0;
let sunnyInflAmnt = 0;
let sunnyBod = 0;
//let rainDay = 0;
let sunnyDay = 0;
for(let idx = 0; idx < data.length; idx++) {
if(data[idx] && data[idx]?.rainEffectDay === 1) {
if(idx > 1){
if(data[idx-1]?.infoRnDay && Number(data[idx]?.infoRnDay) < 3 && Number(data[idx-1]?.infoRnDay) >= 3) {
data[idx]!.infoRnDay = data[idx-1]!.infoRnDay;
}
}
if(idx > 2){
if(data[idx-2]?.infoRnDay && Number(data[idx]?.infoRnDay) < 3 && Number(data[idx-2]?.infoRnDay) >= 3) {
data[idx]!.infoRnDay = data[idx-2]!.infoRnDay;
}
}
data.forEach(item => {
if(item.rainEffectDay == 1){
//rainDay += 1;
//rainInflAmnt += Number(item.inflAmnt);
} else {
sunnyDay += 1;
sunnyInflAmnt += Number(item.inflAmnt);
sunnyBod += Number(item.inflAssctBfrWqltBod);
}
}
});
//const yearRainAmnt = rainInflAmnt===0?0:rainInflAmnt / rainDay;
const yearSunnyAmnt = sunnyInflAmnt===0?0:sunnyInflAmnt / sunnyDay;
const yearSunnyBod = sunnyBod===0?0:sunnyBod / sunnyDay;
//
const rtnData = data.map((item: FacilityWaterQltyProps) => {
dataFormSetting(item)
@@ -636,6 +647,12 @@ export const facilityWaterQltyReducer = (set: (fn: (state: FacilityWaterQltyType
if(item.efflWqltToc){
item.efflWqltToc = Number(Math.round(Number(item.efflWqltToc) * 10)/10).toFixed(1);
}
if(item.inflAssctBfrWqltCod){
item.inflAssctBfrWqltCod = "("+Number(Math.round(Number(item.inflAssctBfrWqltCod) * 10)/10).toFixed(1)+")";
}
if(item.efflWqltCod){
item.efflWqltCod = "("+Number(Math.round(Number(item.efflWqltCod) * 10)/10).toFixed(1)+")";
}
if(item.inflAssctBfrWqltBod){
item.inflAssctBfrWqltBod = Number(Math.round(Number(item.inflAssctBfrWqltBod) * 10)/10).toFixed(1);
}
@@ -665,6 +682,11 @@ export const facilityWaterQltyReducer = (set: (fn: (state: FacilityWaterQltyType
}else{
item.tpInflWqltTp = '';
}
const dayBod = Number(item.inflAssctBfrWqltBod);
const noProcessInflAmnt = roundNumber(((Number(item.inflAmnt) * dayBod) - (yearSunnyAmnt * yearSunnyBod)) / dayBod, 0)
item.noProcessInflAmnt = noProcessInflAmnt && Number(noProcessInflAmnt.replaceAll(',','')) > 0 ? noProcessInflAmnt : '';
return item;
})
set((state: FacilityWaterQltyType) => ({
+96 -95
View File
@@ -1,6 +1,9 @@
import { getFetch } from "@/app/components/api";
import type { TableUpperProps } from "../dashboard";
import DataForm from "@/app/components/common/DataForm";
import DataForm, { roundNumber } from "@/app/components/common/DataForm";
import CalcRainEffect from "@/app/components/common/CalcRainEffect";
import { fetchFacilityWaterQltyListHist } from "../facilityWaterQlty";
import CommaToNumber from "@/app/components/common/CommaToNumber";
/**====================================
* Store - 타입
@@ -36,17 +39,17 @@ export interface ExcelType {
권역:string|'',
단위유역:string|'',
중권역:string|'',
환경청:string|'',
시도: string,
시군구: string,
시설이름: string,
주소: string,
용량: number,
총유입량: number | '',
하수유입량: number | '',
연계처리량: number | '',
총인반류수량: number | '',
방류량: number | '',
환경청:string|'',
"시설용량(m³/일)": number,
"총유입량(m³/일)": number | '',
"하수유입량(m³/일)": number | '',
"연계처리량(m³/일)": number | '',
"총인반류수량(m³/일)": number | '',
"방류량(m³/일)": number | '',
}
export type modalExcelType = {
@@ -70,6 +73,7 @@ export interface FlowRateModalInterface {
efflAmnt : number | '',
infoRnDay : number | string | '',
rainEffectDay : number | string | '' ,
noProcessInflAmnt : number | string | ''
}
export type FlowRateModalProps = {
msrDt : string,
@@ -80,6 +84,7 @@ export type FlowRateModalProps = {
efflAmnt : number,
infoRnDay : number | string | '',
rainEffectDay : number | string | '',
noProcessInflAmnt : number | string | ''
}
/**====================================
@@ -91,53 +96,53 @@ export type FlowRateModalProps = {
*/
// 리스트 (행정별)
const upHeadList1:TableUpperProps[] = [
{ id: "A", title: "행정명", row: 0 ,colSpan: 2 },
{ id: "sido", title: "시도", upName:"upChangeRe", row:1 },
{ id: "gugun", title: "시군구", upName:"upChangeRe", row:1 },
{ id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2},
{ id: "daddr", title: "주소", row: 0, rowSpan: 2},
{ id: "fctCpc", title: "시설용량\n(m³/일)", align:"right", row: 0, rowSpan: 2},
{ id: "totInflAmnt", title: "총 유입입량\n(m³/일)", align:"right", row: 0, rowSpan: 2},
{ id: "inflAmnt", title: "하수유입량\n(m³/일)", align:"right", row: 0, rowSpan: 2},
{ id: "sumFlow", title: '연계처리량\n(m³/일)', align:"right", row: 0, rowSpan: 2},
{ id: "returnAmnt", title: '총인 반류수량\n(m³/일)', align:"right", row: 0, rowSpan: 2},
{ id: "efflAmnt", title: '방류량\n(m³/일)', align:"right", row: 0, rowSpan: 2}
{ id: "A", title: "행정명", row: 0, colSpan: 2, widthPercent: 16 },
{ id: "sido", title: "시도", upName:"upChangeRe", row:1, widthPercent: 8 },
{ id: "gugun", title: "시군구", upName:"upChangeRe", row:1, widthPercent: 8 },
{ id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2, widthPercent: 10},
{ id: "daddr", title: "주소", row: 0, rowSpan: 2 },
{ id: "fctCpc", title: "시설용량\n(m³/일)", align:"right", row: 0, rowSpan: 2, widthPercent: 7 },
{ id: "totInflAmnt", title: "총 유입량\n(m³/일)", align:"right", row: 0, rowSpan: 2, widthPercent: 7 },
{ id: "inflAmnt", title: "하수유입량\n(m³/일)", align:"right", row: 0, rowSpan: 2, widthPercent: 7 },
{ id: "sumFlow", title: '연계처리량\n(m³/일)', align:"right", row: 0, rowSpan: 2, widthPercent: 7 },
{ id: "returnAmnt", title: '총인 반류수량\n(m³/일)', align:"right", row: 0, rowSpan: 2, widthPercent: 7 },
{ id: "efflAmnt", title: '방류량\n(m³/일)', align:"right", row: 0, rowSpan: 2, widthPercent: 7 }
];
// 리스트 (권역별)
const upHeadList2:TableUpperProps[] = [
{ id: "A", title: "유역", row: 0, colSpan: 3},
{ id: "rvbsn", title: "권역", upName:"upChangeRe", row:1 },
{ id: "lgbsn", title: "단위유역", upName:"upChangeRe", row:1 },
{ id: "mdmbsn", title: "중권역", upName:"upChangeRe", row:1 },
{ id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2},
{ id: "daddr", title: "주소", row: 0, rowSpan: 2},
{ id: "fctCpc", title: "시설용량\n(m³/일)", align:"right", row: 0, rowSpan: 2},
{ id: "totInflAmnt", title: "총 유입입량\n(m³/일)", align:"right", row: 0, rowSpan: 2},
{ id: "inflAmnt", title: "하수유입량\n(m³/일)", align:"right", row: 0, rowSpan: 2},
{ id: "sumFlow", title: '연계처리량\n(m³/일)', align:"right", row: 0, rowSpan: 2},
{ id: "returnAmnt", title: '총인 반류수량\n(m³/일)', align:"right", row: 0, rowSpan: 2},
{ id: "efflAmnt", title: '방류량\n(m³/일)', align:"right", row: 0, rowSpan: 2}
{ id: "A", title: "유역", row: 0, colSpan: 3, widthPercent: 24 },
{ id: "rvbsn", title: "권역", upName:"upChangeRe", row:1, widthPercent: 8 },
{ id: "lgbsn", title: "단위유역", upName:"upChangeRe", row:1, widthPercent: 8 },
{ id: "mdmbsn", title: "중권역", upName:"upChangeRe", row:1, widthPercent: 8 },
{ id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2, widthPercent: 10 },
{ id: "daddr", title: "주소", row: 0, rowSpan: 2 },
{ id: "fctCpc", title: "시설용량\n(m³/일)", align:"right", row: 0, rowSpan: 2, widthPercent: 10 },
{ id: "totInflAmnt", title: "총 유입량\n(m³/일)", align:"right", row: 0, rowSpan: 2, widthPercent: 7 },
{ id: "inflAmnt", title: "하수유입량\n(m³/일)", align:"right", row: 0, rowSpan: 2, widthPercent: 7 },
{ id: "sumFlow", title: '연계처리량\n(m³/일)', align:"right", row: 0, rowSpan: 2, widthPercent: 7 },
{ id: "returnAmnt", title: '총인 반류수량\n(m³/일)', align:"right", row: 0, rowSpan: 2, widthPercent: 7 },
{ id: "efflAmnt", title: '방류량\n(m³/일)', align:"right", row: 0, rowSpan: 2, widthPercent: 7 }
];
// 리스트 (환경청별별)
const upHeadList3:TableUpperProps[] = [
{ id: "A", title: "유역", row: 0, colSpan: 3 },
{ id: "rvbsn", title: "권역", upName:"upChangeRe1", row:1 },
{ id: "lgbsn", title: "단위유역", upName:"upChangeRe1", row:1 },
{ id: "mdmbsn", title: "중권역", upName:"upChangeRe1", row:1 },
{ id: "rgnNm", title: "환경청", row:0, rowSpan:2 },
{ id: "B", title: "행정명", row: 0 ,colSpan: 2 },
{ id: "sido", title: "시도", upName:"upChangeRe2", row:1 },
{ id: "gugun", title: "시군구", upName:"upChangeRe2", row:1 },
{ id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2 },
{ id: "A", title: "유역", row: 0, colSpan: 3, widthPercent: 15 },
{ id: "rvbsn", title: "권역", upName:"upChangeRe1", row:1, widthPercent: 5 },
{ id: "lgbsn", title: "단위유역", upName:"upChangeRe1", row:1, widthPercent: 5 },
{ id: "mdmbsn", title: "중권역", upName:"upChangeRe1", row:1, widthPercent: 5 },
{ id: "rgnNm", title: "환경청", row:0, rowSpan:2, widthPercent: 7 },
{ id: "B", title: "행정명", row: 0 ,colSpan: 2, widthPercent: 10 },
{ id: "sido", title: "시도", upName:"upChangeRe2", row:1, widthPercent: 5 },
{ id: "gugun", title: "시군구", upName:"upChangeRe2", row:1, widthPercent: 5 },
{ id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2, widthPercent: 7 },
{ id: "daddr", title: "주소", row: 0, rowSpan: 2 },
{ id: "fctCpc", title: "시설용량\n(m³/일)", align:"right", row: 0, rowSpan: 2 },
{ id: "totInflAmnt", title: "총 유입입량\n(m³/일)", align:"right", row: 0, rowSpan: 2 },
{ id: "inflAmnt", title: "하수유입량\n(m³/일)", align:"right", row: 0, rowSpan: 2 },
{ id: "sumFlow", title: '연계처리량\n(m³/일)', align:"right", row: 0, rowSpan: 2 },
{ id: "returnAmnt", title: '총인 반류수량\n(m³/일)', align:"right", row: 0, rowSpan: 2 },
{ id: "efflAmnt", title: '방류량\n(m³/일)', align:"right", row: 0, rowSpan: 2 }
{ id: "fctCpc", title: "시설용량\n(m³/일)", align:"right", row: 0, rowSpan: 2, widthPercent: 7 },
{ id: "totInflAmnt", title: "총 유입량\n(m³/일)", align:"right", row: 0, rowSpan: 2, widthPercent: 7 },
{ id: "inflAmnt", title: "하수유입량\n(m³/일)", align:"right", row: 0, rowSpan: 2, widthPercent: 7 },
{ id: "sumFlow", title: '연계처리량\n(m³/일)', align:"right", row: 0, rowSpan: 2, widthPercent: 7 },
{ id: "returnAmnt", title: '총인 반류수량\n(m³/일)', align:"right", row: 0, rowSpan: 2, widthPercent: 7 },
{ id: "efflAmnt", title: '방류량\n(m³/일)', align:"right", row: 0, rowSpan: 2, widthPercent: 7 }
];
const flowRateList:flowRateListProps[] = [
@@ -154,6 +159,7 @@ const upHeadListFlowRateModal:TableUpperProps[] = [
{ id: "sumFlow", title: "연계처리량(m³/일)", align:"right"},
{ id: "returnAmnt", title: "총인 반류수량(m³/일)", align:"right"},
{ id: "efflAmnt", title: "방류량(m³/일)", align:"right"},
{ id: "noProcessInflAmnt", title: "미처리하수량(m³/일)", align:"right"},
{ id: "infoRnDay", title: "강우량(mm/일)", align:"right"}
]
@@ -165,7 +171,9 @@ const modalFlowRateListYear:FlowRateModalProps[] = [
====================================*/
const fetchFlowRateList = async (pageNo: number, pageSize: number, searchYear: string, partCd?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => {
try {
const tailStr = partCd ? '/'+ partCd + '/' + nameCd + '/' + fcltCpct + '/' + operationValue + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : ''; const url = '/fclt/flow/' + pageNo + '/' + pageSize + '/' + searchYear + tailStr;
const tailStr = partCd ? '/'+ partCd + '/' + nameCd + '/' + fcltCpct + '/' + operationValue + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : '';
const url = '/fclt/flow/' + pageNo + '/' + pageSize + '/' + searchYear + tailStr;
console.log(url);
const res = await getFetch('fo', url);
return { data: res.data, count: res.count }
} catch (error) {
@@ -174,7 +182,7 @@ const fetchFlowRateList = async (pageNo: number, pageSize: number, searchYear: s
}
}
const fetchFlowRateModalList = async (bscFctCd: string, searchYear: string) => {
export const fetchFlowRateModalList = async (bscFctCd: string, searchYear: string) => {
try {
const url = '/fclt/flow/' + bscFctCd + '/' + searchYear;
const res = await getFetch('fo', url);
@@ -292,12 +300,12 @@ export const flowRateSearchReducer:(set:(fn: (state: FlowRateSearchType) => Flow
시군구: item.gugun,
시설이름: item.bscFctNm,
주소: item.daddr,
용량: item.fctCpc,
총유입량: item.totInflAmnt,
하수유입량: item.inflAmnt,
연계처리량: item.sumFlow,
총인반류수량: item.returnAmnt,
방류량: item.efflAmnt,
"시설용량(m³/일)": item.fctCpc,
"총유입량(m³/일)": CommaToNumber(item.totInflAmnt),
"하수유입량(m³/일)": CommaToNumber(item.inflAmnt),
"연계처리량(m³/일)": CommaToNumber(item.sumFlow),
"총인반류수량(m³/일)": CommaToNumber(item.returnAmnt),
"방류량(m³/일)": CommaToNumber(item.efflAmnt),
});
});
}
@@ -318,50 +326,43 @@ export const flowRateSearchReducer:(set:(fn: (state: FlowRateSearchType) => Flow
},
searchFlowRateModalList: async (bscFctCd: string, searchYear: string) => {
const res = await fetchFlowRateModalList(bscFctCd, searchYear);
const data = res.data;
// 강우영향일 계산 (강우량이 3 초과이면 무조건 강우영향일)
for(let idx = 0; idx < data.length; idx++) {
const item = data[idx];
if(item){
if(item.infoRnDay && Number(item.infoRnDay.toString().trim()) >= 3) {
item.rainEffectDay = 1;
} else {
item.rainEffectDay = 0;
}
}
}
const inflData = CalcRainEffect(res.data);
// 이틀 전, 하루 전이 강우영향일(3 이상)인 경우 해당 날도 강우영향일로 설정
for(let idx = 0; idx < data.length; idx++) {
if(data[idx]) {
// 하루 전이 강우영향일(3 이상)인 경우
if(idx > 0 && data[idx-1]?.infoRnDay && Number(data[idx-1]?.infoRnDay.toString().trim()) >= 3) {
data[idx]!.rainEffectDay = 1;
}
// 이틀 전이 강우영향일(3 이상)인 경우
if(idx > 1 && data[idx-2]?.infoRnDay && Number(data[idx-2]?.infoRnDay.toString().trim()) >= 3) {
data[idx]!.rainEffectDay = 1;
}
}
}
const res2 = await fetchFacilityWaterQltyListHist(searchYear, bscFctCd);
const wqltData = CalcRainEffect(res2?.data.wqltObjs);
for(let idx = 0; idx < data.length; idx++) {
if(data[idx] && data[idx]?.rainEffectDay === 1) {
if(idx > 1){
if(data[idx-1]?.infoRnDay && Number(data[idx]?.infoRnDay) < 3 && Number(data[idx-1]?.infoRnDay.toString().trim()) >= 3) {
data[idx]!.infoRnDay = data[idx-1]!.infoRnDay;
}
}
if(idx > 2){
if(data[idx-2]?.infoRnDay && Number(data[idx]?.infoRnDay) < 3 && Number(data[idx-2]?.infoRnDay.toString().trim()) >= 3) {
data[idx]!.infoRnDay = data[idx-2]!.infoRnDay;
}
}
}
}
/**
* [(강우시 일별유입유량*강우시 일별유입BOD)-(청천시 연평균유입유량*청천시 연평균유입BOD)]​
/강우시 일별유입BOD)
*/
//let rainInflAmnt = 0;
let sunnyInflAmnt = 0;
let sunnyBod = 0;
//let rainDay = 0;
let sunnyDay = 0;
const rtnData = data.map((item: FlowRateModalProps) => {
item.totInflAmnt = Number(item.inflAmnt || 0) + Number(item.sumFlow || 0) + Number(item.returnAmnt || 0)
inflData.forEach(item => {
if(item.rainEffectDay == 1){
//rainDay += 1;
//rainInflAmnt += Number(item.inflAmnt);
} else {
const msrDt = item.msrDt.replaceAll('-','');
sunnyDay += 1;
sunnyInflAmnt += Number(item.inflAmnt);
sunnyBod += Number(wqltData.filter((wqitem)=>wqitem.msrDt === msrDt)[0].inflAssctBfrWqltBod);
}
});
//const yearRainAmnt = rainInflAmnt===0?0:rainInflAmnt / rainDay;
const yearSunnyAmnt = sunnyInflAmnt===0?0:sunnyInflAmnt / sunnyDay;
const yearSunnyBod = sunnyBod===0?0:sunnyBod / sunnyDay;
const rtnData = inflData.map((item: FlowRateModalProps) => {
const dayBod = Number(wqltData.filter(wqitem=>wqitem.msrDt === item.msrDt.replaceAll('-',''))[0].inflAssctBfrWqltBod);
const noProcessInflAmnt = roundNumber(((Number(item.inflAmnt) * dayBod) - (yearSunnyAmnt * yearSunnyBod)) / dayBod, 0)
item.totInflAmnt = Number(item.inflAmnt || 0) + Number(item.sumFlow || 0) + Number(item.returnAmnt || 0);
item.noProcessInflAmnt = noProcessInflAmnt && Number(noProcessInflAmnt.replaceAll(',','')) > 0 ? noProcessInflAmnt : '';
dataFormSetting(item);
return item;
});
+48 -45
View File
@@ -1,7 +1,9 @@
import DataForm from "@/app/components/common/DataForm";
import type { TableUpperProps } from "../dashboard";
import { getFetch } from "@/app/components/api";
import { calRainEffectDay, type ApiResponse, type FlowDataItem } from "../underWaterInput";
import { type ApiResponse, type FlowDataItem } from "../underWaterInput";
import CalcRainEffect from "@/app/components/common/CalcRainEffect";
import { roundUp } from "../common";
export type { TableUpperProps };
/**====================================
* Store - 타입
@@ -45,44 +47,44 @@ const LabelArray:string[] = ['구분', '시도', '시군구','용량별', '시
// 리스트 헤더
const upHeadList1:TableUpperProps[] = [
{ id: "A", title: "행정구역", upSequnce:1, row:0, colSpan:2 },
{ id: "sido", title: "시도", upName:"upChangeRe", upSequnce:1, row:1 },
{ id: "gugun", title: "시군구", upName:"upChangeRe",upSequnce:2, row:1 },
{ id: "bscFctNm", title: "시설명", row:0, rowSpan:2 },
{ id: "sido", title: "시도", upName:"upChangeRe", upSequnce:1, row:1, widthPercent: 10 },
{ id: "gugun", title: "시군구", upName:"upChangeRe",upSequnce:2, row:1, widthPercent: 10 },
{ id: "bscFctNm", title: "시설명", row:0, rowSpan:2, widthPercent: 10 },
{ id: "daddr", title: "주소", row:0, rowSpan:2 },
{ id: "fctCpc", title: "시설용량(m³/일)", row:0, rowSpan:2, align:'right' },
{ id: "spareCapacity", title: "여유용량(m³/일)", row:0, rowSpan:2, align:'right' },
{ id: "variableLoadPercent", title: "변동부하율", row:0, rowSpan:2, align:'right' },
{ id: "classifiedSewerPercent", title: "분류식화율(%)", row:0, rowSpan:2, align:'right' },
{ id: "fctCpc", title: "시설용량(m³/일)", row:0, rowSpan:2, align:'right', widthPercent: 8 },
{ id: "spareCapacity", title: "여유용량(m³/일)", row:0, rowSpan:2, align:'right', widthPercent: 8 },
{ id: "variableLoadPercent", title: "변동부하율(%)", row:0, rowSpan:2, align:'right', widthPercent: 8 },
{ id: "classifiedSewerPercent", title: "분류식화율(%)", row:0, rowSpan:2, align:'right', widthPercent: 8 },
];
const upHeadList2:TableUpperProps[] = [
{ id: "A", title: "유역", upName:"upChangeRe", upSequnce:1, row:0, colSpan:3 },
{ id: "rvbsn", title: "권역", upName:"upChangeRe", upSequnce:1, row:1},
{ id: "lgbsn", title: "단위유역", upName:"upChangeRe", upSequnce:2, row:1},
{ id: "mdmbsn", title: "중권역", upName:"upChangeRe", upSequnce:3, row:1},
{ id: "bscFctNm", title: "시설명", row:0, rowSpan:2 },
{ id: "rvbsn", title: "권역", upName:"upChangeRe", upSequnce:1, row:1, widthPercent: 8 },
{ id: "lgbsn", title: "단위유역", upName:"upChangeRe", upSequnce:2, row:1, widthPercent: 8},
{ id: "mdmbsn", title: "중권역", upName:"upChangeRe", upSequnce:3, row:1, widthPercent: 8},
{ id: "bscFctNm", title: "시설명", row:0, rowSpan:2, widthPercent: 10 },
{ id: "daddr", title: "주소", row:0, rowSpan:2 },
{ id: "fctCpc", title: "시설용량(m³/일)", row:0, rowSpan:2, align:'right' },
{ id: "spareCapacity", title: "여유용량(m³/일)", row:0, rowSpan:2, align:'right' },
{ id: "variableLoadPercent", title: "변동부하율", row:0, rowSpan:2, align:'right' },
{ id: "classifiedSewerPercent", title: "분류식화율(%)", row:0, rowSpan:2, align:'right' },
{ id: "fctCpc", title: "시설용량(m³/일)", row:0, rowSpan:2, align:'right', widthPercent: 8 },
{ id: "spareCapacity", title: "여유용량(m³/일)", row:0, rowSpan:2, align:'right', widthPercent: 8 },
{ id: "variableLoadPercent", title: "변동부하율(%)", row:0, rowSpan:2, align:'right', widthPercent: 8 },
{ id: "classifiedSewerPercent", title: "분류식화율(%)", row:0, rowSpan:2, align:'right', widthPercent: 8 },
];
const upHeadList3:TableUpperProps[] = [
{ id: "A", title: "유역", upName:"upChangeRe", upSequnce:1, row:0, colSpan:3 },
{ id: "rvbsn", title: "권역", upName:"upChangeRe1", upSequnce:1, row:1},
{ id: "lgbsn", title: "단위유역", upName:"upChangeRe1", upSequnce:2, row:1},
{ id: "mdmbsn", title: "중권역", upName:"upChangeRe1", upSequnce:3, row:1},
{ id: "rgnNm", title: "환경청", row:0, rowSpan:2 },
{ id: "rvbsn", title: "권역", upName:"upChangeRe1", upSequnce:1, row:1, widthPercent: 5 },
{ id: "lgbsn", title: "단위유역", upName:"upChangeRe1", upSequnce:2, row:1, widthPercent: 5 },
{ id: "mdmbsn", title: "중권역", upName:"upChangeRe1", upSequnce:3, row:1, widthPercent: 5},
{ id: "rgnNm", title: "환경청", row:0, rowSpan:2, widthPercent: 8 },
{ id: "B", title: "행정구역", upName:"upChangeRe", upSequnce:1, row:0, colSpan:2 },
{ id: "sido", title: "시도", upName:"upChangeRe2", upSequnce:1, row:1 },
{ id: "gugun", title: "시군구", upName:"upChangeRe2",upSequnce:2, row:1 },
{ id: "bscFctNm", title: "시설명", row:0, rowSpan:2 },
{ id: "sido", title: "시도", upName:"upChangeRe2", upSequnce:1, row:1, widthPercent: 5 },
{ id: "gugun", title: "시군구", upName:"upChangeRe2",upSequnce:2, row:1, widthPercent: 5 },
{ id: "bscFctNm", title: "시설명", row:0, rowSpan:2, widthPercent: 10 },
{ id: "daddr", title: "주소", row:0, rowSpan:2 },
{ id: "fctCpc", title: "시설용량(m³/일)", row:0, rowSpan:2, align:'right' },
{ id: "spareCapacity", title: "여유용량(m³/일)", row:0, rowSpan:2, align:'right' },
{ id: "variableLoadPercent", title: "변동부하율", row:0, rowSpan:2, align:'right' },
{ id: "classifiedSewerPercent", title: "분류식화율(%)", row:0, rowSpan:2, align:'right' },
{ id: "fctCpc", title: "시설용량(m³/일)", row:0, rowSpan:2, align:'right', widthPercent: 8 },
{ id: "spareCapacity", title: "여유용량(m³/일)", row:0, rowSpan:2, align:'right', widthPercent: 8 },
{ id: "variableLoadPercent", title: "변동부하율(%)", row:0, rowSpan:2, align:'right', widthPercent: 8 },
{ id: "classifiedSewerPercent", title: "분류식화율(%)", row:0, rowSpan:2, align:'right', widthPercent: 8 },
];
const planSewageList:PlanSewageProps[] = [
@@ -112,10 +114,10 @@ export type ExcelType = {
시군구: string;
시설이름: string;
주소: string;
시설용량: number;
여유용량: number;
변동부하율 : number;
분류식화율 : number;
"시설용량(m³/일)": number;
"여유용량(m³/일)": number;
"변동부하율(%)" : number;
"분류식화율(%)" : number;
}
const dataFormSetting=(item : PlanSewageProps)=> {
@@ -182,22 +184,25 @@ export const planSewageReducer:(set:(fn: (state: PlanSewageType) => PlanSewageTy
const data = res.data
const processedData = await Promise.all(data.map(async (item:PlanSewageProps) => {
const res2 = await getFetch('fo', '/fclt/flow/' + item.bscFctCd + '/' + searchYear) as ApiResponse;
const calData = calRainEffectDay(res2.data, 'SUNNY');
const calData = CalcRainEffect(res2.data, 'SUNNY');
let sumInflAmntSunny = 0;
let avgInflAmntSunny = 0;
let maxInflAmntSunny = 0;
calData.forEach((flowItem:FlowDataItem) => {
sumInflAmntSunny += Number(flowItem.inflAmnt);
})
if(Number(flowItem.inflAmnt) > maxInflAmntSunny){
maxInflAmntSunny = Number(flowItem.inflAmnt);
}
});
avgInflAmntSunny = sumInflAmntSunny / calData.length;
item.avgInflAmntSunny = avgInflAmntSunny;
if(item.bscFctCd === '11200PB001R'){
console.log('avgInflAmntSunny : ',item.avgInflAmntSunny);
console.log('calData : ',calData);
}
item.avgInflAmntSunny = roundUp(avgInflAmntSunny, 0);
item.maxInflAmntSunny = roundUp(maxInflAmntSunny, 0);
return item;
}));
/**
* 결과데이터 계산
* (1) 여유용량 = 시설용량 - 건기시 평균유량
@@ -205,8 +210,6 @@ export const planSewageReducer:(set:(fn: (state: PlanSewageType) => PlanSewageTy
* (3) 분류식화율 = 분류식지역 면적(㎢)/처리구역 면적합계(㎢) ×100
*/
const resultData = processedData.map((item:PlanSewageProps) => {
console.log('item.fctCpc : ',item.fctCpc);
console.log('item.avgInflAmntSunny : ',item.avgInflAmntSunny);
item.spareCapacity = Number(item.fctCpc) - Number(item.avgInflAmntSunny);
item.variableLoadPercent = item.maxInflAmntSunny && item.maxInflAmntSunny!==0 ? Number(item.maxInflAmntSunny) / Number(item.avgInflAmntSunny) : 0;
item.classifiedSewerPercent = item.sprtProcZoneAr && item.sprtProcZoneAr!==0 ? Number(item.sprtProcZoneAr) / Number(item.procZoneSm) * 100 : 0;
@@ -229,10 +232,10 @@ export const planSewageReducer:(set:(fn: (state: PlanSewageType) => PlanSewageTy
시도: item.sido,
시군구: item.gugun,
주소: item.daddr,
시설용량: item.fctCpc,
여유용량: item.spareCapacity,
변동부하율: item.variableLoadPercent,
분류식화율: item.classifiedSewerPercent,
"시설용량(m³/일)": item.fctCpc,
"여유용량(m³/일)": item.spareCapacity,
"변동부하율(%)": item.variableLoadPercent,
"분류식화율(%)": item.classifiedSewerPercent,
})
})
}
+67 -67
View File
@@ -63,25 +63,25 @@ export interface ExcelType {
시설코드: string,
시설명: string,
주소: string,
시설용량: number | '',
증설계획기존: number | '',
증설계획현재: number | '',
증설계획1단계: number | '',
증설계획2단계: number | '',
증설계획3단계: number | '',
증설계획4단계: number | '',
처리인구기존: number | '',
처리인구현재: number | '',
처리인구1단계: number | '',
처리인구2단계: number | '',
처리인구3단계: number | '',
처리인구4단계: number | '',
처리구역기존: number | '',
처리구역현재: number | '',
처리구역1단계: number | '',
처리구역2단계: number | '',
처리구역3단계: number | '',
처리구역4단계: number | '',
"시설옹량(m³/일)": number | '',
"증설계획기존(m³/일)": number | '',
"증설계획현재(m³/일)": number | '',
"증설계획1단계(m³/일)": number | '',
"증설계획2단계(m³/일)": number | '',
"증설계획3단계(m³/일)": number | '',
"증설계획4단계(m³/일)": number | '',
"처리인구기존(인)": number | '',
"처리인구현재(인)": number | '',
"처리인구1단계(인)": number | '',
"처리인구2단계(인)": number | '',
"처리인구3단계(인)": number | '',
"처리인구4단계(인)": number | '',
"처리구역기존(km²)": number | '',
"처리구역현재(km²)": number | '',
"처리구역1단계(km²)": number | '',
"처리구역2단계(km²)": number | '',
"처리구역3단계(km²)": number | '',
"처리구역4단계(km²)": number | '',
처리구역: string | ''
}
@@ -128,35 +128,35 @@ const ProcessFacilityLabelArray:string[] = ['구분', '시도', '시군구','용
// 리스트 헤더(행정별)
const upHeadList1:TableUpperProps[] = [
{ id: "A", title: "행정구역", colSpan:2, rowSpan:2, row:0},
{ id: "sido", title: "시도", upName:"upChangeRe", row:2 },
{ id: "sigungo", title: "시군구", upName:"upChangeRe", row:2 },
{ id: "swtrmtFcltNm", title: "시설명", rowSpan:3, row:0},
{ id: "location", title: "주소", rowSpan:3, row:0, },
{ id: "fctCpc", title: "시설용량(m³/일)", align:"right", rowSpan:3, row:0},
{ id: "B", title: "시설계획", colSpan:19, row:0},
{ id: "C", title: "증설계획(m³/일)", colSpan:6, row:1},
{ id: "planSwageQntSumDt4", title: "기승인\n4단계", row:2, align:"right"},
{ id: "planSwageQntSum", title: "현재", row:2, align:"right"},
{ id: "planSwageQntSumDc1", title: "1단계", row:2, align:"right"},
{ id: "planSwageQntSumDc2", title: "2단계", row:2, align:"right"},
{ id: "planSwageQntSumDc3", title: "3단계", row:2, align:"right"},
{ id: "planSwageQntSumDc4", title: "4단계", row:2, align:"right"},
{ id: "D", title: "처리인구(인)", colSpan:6, row:1},
{ id: "swtrmtPpltnCntDt4", title: "기승인\n4단계", row:2, align:"right"},
{ id: "swtrmtPpltnCnt", title: "현재", row:2, align:"right"},
{ id: "swtrmtPpltnCntDc1", title: "1단계", row:2, align:"right"},
{ id: "swtrmtPpltnCntDc2", title: "2단계", row:2, align:"right"},
{ id: "swtrmtPpltnCntDc3", title: "3단계", row:2, align:"right"},
{ id: "swtrmtPpltnCntDc4", title: "4단계", row:2, align:"right"},
{ id: "E", title: "처리구역(km²)", colSpan:7, row:1},
{ id: "swtrmtZoneAreaDt4", title: "기승인\n4단계", row:2, align:"right"},
{ id: "swtrmtZoneArea", title: "현재", row:2, align:"right"},
{ id: "swtrmtZoneAreaDc1", title: "1단계", row:2, align:"right"},
{ id: "swtrmtZoneAreaDc2", title: "2단계", row:2, align:"right"},
{ id: "swtrmtZoneAreaDc3", title: "3단계", row:2, align:"right"},
{ id: "swtrmtZoneAreaDc4", title: "4단계", row:2, align:"right"},
{ id: "trtDstr", title: "처리구역", row:2}
{ id: "A", title: "행정구역", colSpan:2, rowSpan:2, row:0 },
{ id: "sido", title: "시도", upName:"upChangeRe", row:2, widthPercent:4 },
{ id: "sigungo", title: "시군구", upName:"upChangeRe", row:2, widthPercent:4 },
{ id: "swtrmtFcltNm", title: "시설명", rowSpan:3, row:0, widthPercent: 8 },
{ id: "location", title: "주소", rowSpan:3, row:0 },
{ id: "fctCpc", title: "시설용량(m³/일)", align:"right", rowSpan:3, row:0, widthPercent: 5 },
{ id: "B", title: "시설계획", colSpan:19, row: 0 },
{ id: "C", title: "증설계획(m³/일)", colSpan:6, row: 1 },
{ id: "planSwageQntSumDt4", title: "기승인\n4단계", row:2, align:"right", widthPercent: 2.5 },
{ id: "planSwageQntSum", title: "현재", row:2, align:"right", widthPercent: 2.5 },
{ id: "planSwageQntSumDc1", title: "1단계", row:2, align:"right", widthPercent: 2.5 },
{ id: "planSwageQntSumDc2", title: "2단계", row:2, align:"right", widthPercent: 2.5 },
{ id: "planSwageQntSumDc3", title: "3단계", row:2, align:"right", widthPercent: 2.5 },
{ id: "planSwageQntSumDc4", title: "4단계", row:2, align:"right", widthPercent: 2.5 },
{ id: "D", title: "처리인구(인)", colSpan:6, row:1 },
{ id: "swtrmtPpltnCntDt4", title: "기승인\n4단계", row:2, align:"right", widthPercent: 2.5 },
{ id: "swtrmtPpltnCnt", title: "현재", row:2, align:"right", widthPercent: 2.5 },
{ id: "swtrmtPpltnCntDc1", title: "1단계", row:2, align:"right", widthPercent: 2.5 },
{ id: "swtrmtPpltnCntDc2", title: "2단계", row:2, align:"right", widthPercent: 2.5 },
{ id: "swtrmtPpltnCntDc3", title: "3단계", row:2, align:"right", widthPercent: 2.5 },
{ id: "swtrmtPpltnCntDc4", title: "4단계", row:2, align:"right", widthPercent: 2.5 },
{ id: "E", title: "처리구역(km²)", colSpan:7, row:1 },
{ id: "swtrmtZoneAreaDt4", title: "기승인\n4단계", row:2, align:"right", widthPercent: 2.5 },
{ id: "swtrmtZoneArea", title: "현재", row:2, align:"right", widthPercent: 2.5 },
{ id: "swtrmtZoneAreaDc1", title: "1단계", row:2, align:"right", widthPercent: 2.5 },
{ id: "swtrmtZoneAreaDc2", title: "2단계", row:2, align:"right", widthPercent: 2.5 },
{ id: "swtrmtZoneAreaDc3", title: "3단계", row:2, align:"right", widthPercent: 2.5 },
{ id: "swtrmtZoneAreaDc4", title: "4단계", row:2, align:"right", widthPercent: 2.5 },
{ id: "trtDstr", title: "처리구역", row:2 }
];
const processAreaList:ProcessAreaProps[] = [
@@ -385,25 +385,25 @@ export const processAreaReducer:(set:SetStateFunction)=>ProcessAreaActions=(set:
시설코드: item.swtrmtFcltCd,
시설명: item.swtrmtFcltNm,
주소: item.location,
시설용량: item.fctCpc,
증설계획기존: item.planSwageQntSumDt4,
증설계획현재: item.planSwageQntSum,
증설계획1단계: item.planSwageQntSumDc1,
증설계획2단계: item.planSwageQntSumDc2,
증설계획3단계: item.planSwageQntSumDc3,
증설계획4단계: item.planSwageQntSumDc4,
처리인구기존: item.swtrmtPpltnCntDt4,
처리인구현재: item.swtrmtPpltnCnt,
처리인구1단계: item.swtrmtPpltnCntDc1,
처리인구2단계: item.swtrmtPpltnCntDc2,
처리인구3단계: item.swtrmtPpltnCntDc3,
처리인구4단계: item.swtrmtPpltnCntDc4,
처리구역기존: item.swtrmtZoneAreaDt4,
처리구역현재: item.swtrmtZoneArea,
처리구역1단계: item.swtrmtZoneAreaDc1,
처리구역2단계: item.swtrmtZoneAreaDc2,
처리구역3단계: item.swtrmtZoneAreaDc3,
처리구역4단계: item.swtrmtZoneAreaDc4,
"시설옹량(m³/일)": item.fctCpc,
"증설계획기존(m³/일)": item.planSwageQntSumDt4,
"증설계획현재(m³/일)": item.planSwageQntSum,
"증설계획1단계(m³/일)": item.planSwageQntSumDc1,
"증설계획2단계(m³/일)": item.planSwageQntSumDc2,
"증설계획3단계(m³/일)": item.planSwageQntSumDc3,
"증설계획4단계(m³/일)": item.planSwageQntSumDc4,
"처리인구기존(인)": item.swtrmtPpltnCntDt4,
"처리인구현재(인)": item.swtrmtPpltnCnt,
"처리인구1단계(인)": item.swtrmtPpltnCntDc1,
"처리인구2단계(인)": item.swtrmtPpltnCntDc2,
"처리인구3단계(인)": item.swtrmtPpltnCntDc3,
"처리인구4단계(인)": item.swtrmtPpltnCntDc4,
"처리구역기존(km²)": item.swtrmtZoneAreaDt4,
"처리구역현재(km²)": item.swtrmtZoneArea,
"처리구역1단계(km²)": item.swtrmtZoneAreaDc1,
"처리구역2단계(km²)": item.swtrmtZoneAreaDc2,
"처리구역3단계(km²)": item.swtrmtZoneAreaDc3,
"처리구역4단계(km²)": item.swtrmtZoneAreaDc4,
처리구역: item.trtDstr
});
});
+52 -48
View File
@@ -44,9 +44,9 @@ export interface ExcelType {
시군구: string,
시설이름: string,
주소: string,
시설용량: number | '',
계획유입수질: number | '',
설계유입수질: number | '',
"시설용량(m³/일)": number | '',
"계획유입수질(mg/L)": number | '',
"설계유입수질(mg/L)": number | '',
공법: string,
가동개시일: string,
준공일: string,
@@ -118,7 +118,7 @@ export type fcltyHistInfoProps = {
sitArea : number,
trtDstrArea : number,
swrTrtPopl : number,
fcltCpc : number | ''
fctCpc : number | ''
}
// 시설 수질정보
@@ -162,52 +162,56 @@ const ProcessFacilityLabelArray:string[] = ['구분', '시도', '시군구','용
// 리스트 헤더
const upHeadList1:TableUpperProps[] = [
{ id: "sido", title: "시도", upName:"upChangeRe", upSequnce:1 },
{ id: "gugun", title: "시군구", upName:"upChangeRe",upSequnce:2 },
{ id: "bscFctNm", title: "시설명"},
{ id: "daddr", title: "주소"},
{ id: "fctCpc", title: "시설용량\n(m³/일)", align: 'right'},
{ id: "plInflWqltBod", title: "계획유입수질\n(mg/L)", align:"right"},
{ id: "dsInflWqltBod", title: "설계유입수질\n(mg/L)", align:"right"},
{ id: "trtFrfNm", title: '공법'},
{ id: "rnDt", title: '가동개시일'},
{ id: "cmplDt", title: '준공일' },
{ id: "trstOprEtpNm", title: '관리대행업자'}
{ id: "A", title: "행정명", colSpan: 2, row: 0, widthPercent: 10 },
{ id: "sido", title: "시도", upName:"upChangeRe", row: 1, upSequnce:1, widthPercent: 5 },
{ id: "gugun", title: "시군구", upName:"upChangeRe", row: 1, upSequnce:2, widthPercent: 5 },
{ id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2, widthPercent: 8 },
{ id: "daddr", title: "주소", row: 0, rowSpan: 2 },
{ id: "fctCpc", title: "시설용량\n(m³/일)", row: 0, align: 'right', rowSpan: 2, widthPercent: 5 },
{ id: "plInflWqltBod", title: "계획유입수질\n(mg/L)", row: 0, align:"right", rowSpan: 2, widthPercent: 5 },
{ id: "dsInflWqltBod", title: "설계유입수질\n(mg/L)", row: 0, align:"right", rowSpan: 2, widthPercent: 5 },
{ id: "trtFrfNm", title: '공법', row: 0, rowSpan: 2 },
{ id: "rnDt", title: '가동개시일', row: 0, rowSpan: 2, widthPercent: 5 },
{ id: "cmplDt", title: '준공일', row: 0, rowSpan: 2, widthPercent: 5 },
{ id: "trstOprEtpNm", title: '관리대행업자', row: 0, rowSpan: 2 , widthPercent: 14}
];
// 처리시설 리스트 (유역)
const upHeadList2:TableUpperProps[] = [
{ id: "rvbsn", title: "권역", upName:"upChangeRe", upSequnce:1},
{ id: "lgbsn", title: "단위유역", upName:"upChangeRe", upSequnce:2},
{ id: "mdmbsn", title: "중권역", upName:"upChangeRe", upSequnce:3},
{ id: "bscFctNm", title: "시설명"},
{ id: "daddr", title: "주소"},
{ id: "fctCpc", title: "시설용량\n(m³/일)", align: 'right'},
{ id: "plInflWqltBod", title: "계획유입수질\n(mg/L)", align:'right'},
{ id: "dsInflWqltBod", title: "설계유입수질\n(mg/L)", align:'right'},
{ id: "trtFrfNm", title: '공법'},
{ id: "rnDt", title: '가동개시일'},
{ id: "cmplDt", title: '준공일' },
{ id: "trstOprEtpNm", title: '관리대행업자'}
{ id: "A", title: "유역", colSpan: 3, row: 0, widthPercent: 15 },
{ id: "rvbsn", title: "권역", row: 1, widthPercent: 5 },
{ id: "lgbsn", title: "단위유역", row: 1, widthPercent: 5 },
{ id: "mdmbsn", title: "중권역", row: 1, widthPercent: 5 },
{ id: "bscFctNm", title: "시설명", rowSpan: 2,row: 0, widthPercent: 8 },
{ id: "daddr", title: "주소", rowSpan: 2,row: 0 },
{ id: "fctCpc", title: "시설용량\n(m³/일)", rowSpan: 2,row: 0, widthPercent: 5, align: 'right'},
{ id: "plInflWqltBod", title: "계획유입수질\n(mg/L)", rowSpan: 2,row: 0, widthPercent: 6, align:'right'},
{ id: "dsInflWqltBod", title: "설계유입수질\n(mg/L)", rowSpan: 2,row: 0, widthPercent: 6, align:'right'},
{ id: "trtFrfNm", title: '공법', rowSpan: 2,row: 0 },
{ id: "rnDt", title: '가동개시일', rowSpan: 2,row: 0, widthPercent: 5 },
{ id: "cmplDt", title: '준공일', rowSpan: 2,row: 0, widthPercent: 5 },
{ id: "trstOprEtpNm", title: '관리대행업자', rowSpan: 2,row: 0, widthPercent: 14 }
];
// 처리시설 리스트 (환경청청)
const upHeadList3:TableUpperProps[] = [
{ id: "rvbsn", title: "권역", upName:"upChangeRe1", upSequnce:1},
{ id: "lgbsn", title: "단위유역", upName:"upChangeRe1", upSequnce:2},
{ id: "mdmbsn", title: "중권역", upName:"upChangeRe1", upSequnce:3},
{ id: "rgnNm", title: "환경청"},
{ id: "sido", title: "시도", upName:"upChangeRe2", upSequnce:1 },
{ id: "gugun", title: "시군구", upName:"upChangeRe2",upSequnce:2 },
{ id: "bscFctNm", title: "시설명"},
{ id: "daddr", title: "주소"},
{ id: "fctCpc", title: "시설용량\n(m³/일)", align: 'right'},
{ id: "plInflWqltBod", title: "계획유입수질\n(mg/L)", align:'right'},
{ id: "dsInflWqltBod", title: "설계유입수질\n(mg/L)", align:'right'},
{ id: "trtFrfNm", title: '공법'},
{ id: "rnDt", title: '가동개시일'},
{ id: "cmplDt", title: '준공일' },
{ id: "trstOprEtpNm", title: '관리대행업자'}
{ id: "A", title: "유역", colSpan: 3, row: 0, widthPercent: 12 },
{ id: "rvbsn", title: "권역", row: 1, widthPercent: 4 },
{ id: "lgbsn", title: "단위유역", row: 1, widthPercent: 4},
{ id: "mdmbsn", title: "중권역", row: 1, widthPercent: 4 },
{ id: "rgnNm", title: "환경청", row: 0, rowSpan: 2, widthPercent: 6 },
{ id: "B", title: "행정명", colSpan: 2, row: 0, widthPercent: 8 },
{ id: "sido", title: "시도", row: 1, widthPercent: 4 },
{ id: "gugun", title: "시군구", row: 1, widthPercent: 4 },
{ id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2, widthPercent: 8 },
{ id: "daddr", title: "주소", row: 0, rowSpan: 2 },
{ id: "fctCpc", title: "시설용량\n(m³/일)", row: 0, rowSpan: 2, align: 'right', widthPercent: 5 },
{ id: "plInflWqltBod", title: "계획유입수질\n(mg/L)", row: 0, rowSpan: 2, align:'right', widthPercent: 5 },
{ id: "dsInflWqltBod", title: "설계유입수질\n(mg/L)", row: 0, rowSpan: 2, align:'right', widthPercent: 5 },
{ id: "trtFrfNm", title: '공법', row: 0, rowSpan: 2 },
{ id: "rnDt", title: '가동개시일', row: 0, rowSpan: 2, widthPercent: 5 },
{ id: "cmplDt", title: '준공일', row: 0, rowSpan: 2, widthPercent: 5 },
{ id: "trstOprEtpNm", title: '관리대행업자', row: 0, rowSpan: 2, widthPercent: 14 }
];
const processFacilityList:facilityListProps[] = [
@@ -345,7 +349,7 @@ const gridListFcltyHistInfo:fcltyHistInfoProps[] = [
sitArea : 0,
trtDstrArea : 0,
swrTrtPopl : 0,
fcltCpc : 860000
fctCpc : 860000
}
];
@@ -456,7 +460,7 @@ const fetchFacilityHistInfo = async (facilityCd:string ): Promise<fcltyHistInfoP
};
// 시설정보 수질정보 데이터 호출
const fetchFacilityWaterQltyInfo = async (facilityCd:string ): Promise<fcltyWaterQltyInfoProps[]> => {
export const fetchFacilityWaterQltyInfo = async (facilityCd:string ): Promise<fcltyWaterQltyInfoProps[]> => {
try {
const res = await getFetch('fo', '/prcsFclt/info/history/'+facilityCd);
const data = res.data;
@@ -623,13 +627,13 @@ export const processFacilityReducer:(set:SetStateFunction)=>ProcessFacilityActio
시군구: item.gugun,
시설이름: item.bscFctNm,
주소: item.daddr,
시설용량: item.fctCpc ? Number(item.fctCpc) : '',
계획유입수질: item.plInflWqltBod ? Number(item.plInflWqltBod) : '',
설계유입수질: item.dsInflWqltBod ? Number(item.dsInflWqltBod) : '',
"시설용량(m³/일)": item.fctCpc ? Number(item.fctCpc.toString().replaceAll(',','')) : '',
"계획유입수질(mg/L)": item.plInflWqltBod ? Number(item.plInflWqltBod) : '',
"설계유입수질(mg/L)": item.dsInflWqltBod ? Number(item.dsInflWqltBod) : '',
공법: item.trtFrfNm,
가동개시일: item.rnDt,
준공일: item.cmplDt,
관리대행업자: item.mnstr,
관리대행업자: item.trstOprEtpNm,
})
})
}
+171 -76
View File
@@ -1,8 +1,9 @@
import { getFetch } from "@/app/components/api";
import DataForm from "@/app/components/common/DataForm";
import CalcRainEffect from "@/app/components/common/CalcRainEffect";
import DataForm, { roundNumber } from "@/app/components/common/DataForm";
import type { TableUpperProps } from "../dashboard";
import { fetchFacilityWaterQltyListHist } from "../facilityWaterQlty";
import { calRainEffectDay } from "../underWaterInput";
import type { FlowResponse } from "../sewageOccur";
export type { TableUpperProps };
/**====================================
* Store - 타입
@@ -30,6 +31,9 @@ export type RdiProps = {
lgbsn : string,
mdmbsn : string,
rainEffectDay : number, // 강우영향일
chungchunFlow : string | number | '',
rainCalInflAmnt : string | number | '',
properYn : string,
}
export interface RdiInterface {
@@ -44,11 +48,15 @@ export interface RdiInterface {
inflAmnt : number,
winterAvgBodLowRainfall : number,
rdiiValue : number,
infoRnDay : number,
infoRnDay : number | string,
rgnNm : string,
rvbsn : string,
lgbsn : string,
mdmbsn : string,
rainEffectDay : number, // 강우영향일
chungchunFlow : string | number | '',
rainCalInflAmnt : string | number | '',
properYn : string,
}
// 모달
@@ -79,67 +87,79 @@ export interface ExcelType {
시군구: string,
시설명: string,
주소: string,
시설용량: number,
하절기강우일최저유입BOD: number | '',
하절기최저유입BOD유입유량: number | string | '',
동절기청천시유입BOD: number | '',
RDII추정 : number | '',
RDII추정시일강수량 : number | '',
"시설용량(m³/일)": number,
"청천시유입하수량(m³/일)": string | number | '',
"하절기강우일최저유입BOD(mg/L)": number | '',
"하절기최저유입BOD유입유량(m³/일)": number | string | '',
"동절기청천시유입BOD(mg/L)": number | '',
"RDII추정" : number | '',
"RDII추정시일강수량(mm)": number | '',
"강우시총추정유입량(m³/일)" : string | number | '',
적정여부 : string,
}
// 리스트 헤더
const upHeadList1:TableUpperProps[] = [
{ id: "A", title: "행정구역", row:0, colSpan:2 },
{ id: "sido", title: "시도", upName:"upChangeRe", upSequnce:1, row:1 },
{ id: "sigungo", title: "시군구", upName:"upChangeRe",upSequnce:2, row:1 },
{ id: "bscFctNm", title: "시설명", row:0, rowSpan:2 },
{ id: "sido", title: "시도", row:1, widthPercent: 6 },
{ id: "sigungo", title: "시군구", row:1, widthPercent: 6 },
{ id: "bscFctNm", title: "시설명", row:0, rowSpan:2, widthPercent: 7 },
{ id: "daddr", title: "주소", row:0, rowSpan:2 },
{ id: "fctCpc", title: "시설용량\n(m³/일)", align:"right", row:0, rowSpan:2 },
{ id: "fctCpc", title: "시설용량\n(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 7 },
{ id: "chungchunFlow", title: "청천시 유입하수량\n(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 7 },
{ id: "B", title: "하절기 운영현황(6~8월)", row:0, colSpan:2 },
{ id: "summerMinBodValue", title: "3mm 이상 강우일 중 최저 유입BOD\n(mg/L)", align:"right", row:1 },
{ id: "inflAmnt", title: "하절기최저유입BOD유입유량\n(m³/일)", row:1, align:"right" },
{ id: "summerMinBodValue", title: "3mm 이상 강우일 중\n최저 유입BOD\n(mg/L)", align:"right", row:1, widthPercent: 7 },
{ id: "inflAmnt", title: "하절기최저유입\nBOD유입유량\n(m³/일)", row:1, align:"right", widthPercent: 7 },
{ id: "C", title: "동절기 운영현황(1~2월)", row:0 },
{ id: "winterAvgBodLowRainfall", title: "청천시 유입BOD\n(mg/L)", row:1, align:"right" },
{ id: "rdiiValue", title: "RDII추정", row:0, rowSpan:2, align:"right" },
{ id: "infoRnDay", title: "RDII추정시일강수량\n(mm)", row:0, rowSpan:2, align:"right" },
{ id: "winterAvgBodLowRainfall", title: "청천시 유입BOD\n(mg/L)", row:1, align:"right", widthPercent: 8 },
{ id: "rdiiValue", title: "RDII추정", row:0, rowSpan:2, align:"right", widthPercent: 8 },
{ id: "infoRnDay", title: "RDII추정시\n일강수량\n(mm)", row:0, rowSpan:2, align:"right", widthPercent: 7 },
{ id: "rainCalInflAmnt", title: "강우시\n총 추정유입량\n(m³/일)", row:0, rowSpan:2, align:"right", widthPercent: 6 },
{ id: "properYn", title: "적정여부", row:0, rowSpan:2, widthPercent: 6 },
];
const upHeadList2:TableUpperProps[] = [
{ id: "A", title: "유역", row:0, colSpan:3 },
{ id: "rvbsn", title: "권역", upName:"upChangeRe", upSequnce:1, row:1 },
{ id: "lgbsn", title: "단위유역", upName:"upChangeRe", upSequnce:2, row:1 },
{ id: "mdmbsn", title: "중권역", upName:"upChangeRe", upSequnce:3, row:1 },
{ id: "bscFctNm", title: "시설명", row:0, rowSpan:2 },
{ id: "rvbsn", title: "권역", row:1, widthPercent: 5 },
{ id: "lgbsn", title: "단위유역", row:1, widthPercent: 5 },
{ id: "mdmbsn", title: "중권역", row:1, widthPercent: 5 },
{ id: "bscFctNm", title: "시설명", row:0, rowSpan:2, widthPercent: 7 },
{ id: "daddr", title: "주소", row:0, rowSpan:2 },
{ id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2 },
{ id: "fctCpc", title: "시설용량\n(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 7 },
{ id: "chungchunFlow", title: "청천시 유입하수량\n(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 7 },
{ id: "B", title: "하절기 운영현황(6~8월)", row:0, colSpan:2 },
{ id: "summerMinBodValue", title: "하절기강우일최저유입BOD", align:"right", row:1 },
{ id: "inflAmnt", title: "하절기최저유입BOD유입유량", row:1, align:"right" },
{ id: "summerMinBodValue", title: "3mm 이상 강우일 중\n최저 유입BOD\n(mg/L)", align:"right", row:1, widthPercent: 7 },
{ id: "inflAmnt", title: "하절기최저유입\nBOD유입유량\n(m³/일)", row:1, align:"right", widthPercent: 7 },
{ id: "D", title: "동절기 운영현황(1~2월)", row:0 },
{ id: "winterAvgBodLowRainfall", title: "동절기청천시유입BOD", row:1, align:"right" },
{ id: "rdiiValue", title: "RDII추정", row:0, rowSpan:2, align:"right" },
{ id: "infoRnDay", title: "RDII추정시일강수량", row:0, rowSpan:2, align:"right" },
{ id: "winterAvgBodLowRainfall", title: "청천시 유입BOD\n(mg/L)", row:1, align:"right", widthPercent: 8 },
{ id: "rdiiValue", title: "RDII추정", row:0, rowSpan:2, align:"right", widthPercent: 7 },
{ id: "infoRnDay", title: "RDII추정시\n일강수량\n(mm)", row:0, rowSpan:2, align:"right", widthPercent: 7 },
{ id: "rainCalInflAmnt", title: "강우시\n총 추정유입량\n(m³/일)", row:0, rowSpan:2, align:"right", widthPercent: 6 },
{ id: "properYn", title: "적정여부", row:0, rowSpan:2, widthPercent: 6 },
];
const upHeadList3:TableUpperProps[] = [
{ id: "A", title: "유역", row:0, colSpan:3 },
{ id: "rvbsn", title: "권역", upName:"upChangeRe1", upSequnce:1, row:1 },
{ id: "lgbsn", title: "단위유역", upName:"upChangeRe1", upSequnce:2, row:1 },
{ id: "mdmbsn", title: "중권역", upName:"upChangeRe1", upSequnce:3, row:1 },
{ id: "rgnNm", title: "환경청", row:0, rowSpan:2 },
{ id: "rvbsn", title: "권역", row:1, widthPercent: 4 },
{ id: "lgbsn", title: "단위유역", row:1, widthPercent: 4 },
{ id: "mdmbsn", title: "중권역", row:1, widthPercent: 4 },
{ id: "rgnNm", title: "환경청", row:0, rowSpan:2, widthPercent: 6 },
{ id: "B", title: "행정구역", row:0, colSpan:2 },
{ id: "sido", title: "시도", upName:"upChangeRe2", upSequnce:1, row:1 },
{ id: "sigungo", title: "시군구", upName:"upChangeRe2",upSequnce:2, row:1 },
{ id: "bscFctNm", title: "시설명", row:0, rowSpan:2 },
{ id: "sido", title: "시도", upName:"upChangeRe2", upSequnce:1, row:1, widthPercent: 4 },
{ id: "sigungo", title: "시군구", upName:"upChangeRe2",upSequnce:2, row:1, widthPercent: 4 },
{ id: "bscFctNm", title: "시설명", row:0, rowSpan:2, widthPercent: 6 },
{ id: "daddr", title: "주소", row:0, rowSpan:2 },
{ id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2 },
{ id: "fctCpc", title: "시설용량\n(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 5 },
{ id: "chungchunFlow", title: "청천시 유입하수량\n(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 6 },
{ id: "C", title: "하절기 운영현황(6~8월)", row:0, colSpan:2 },
{ id: "summerMinBodValue", title: "하절기강우일최저유입BOD", align:"right", row:1 },
{ id: "inflAmnt", title: "하절기최저유입BOD유입유량", row:1, align:"right" },
{ id: "summerMinBodValue", title: "3mm 이상 강우일 중\n최저 유입BOD\n(mg/L)", align:"right", row:1, widthPercent: 6 },
{ id: "inflAmnt", title: "하절기최저유입\nBOD유입유량\n(m³/일)", row:1, align:"right", widthPercent: 6 },
{ id: "D", title: "동절기 운영현황(1~2월)", row:0 },
{ id: "winterAvgBodLowRainfall", title: "동절기청천시유입BOD", row:1, align:"right" },
{ id: "rdiiValue", title: "RDII추정", row:0, rowSpan:2, align:"right" },
{ id: "infoRnDay", title: "RDII추정시일강수량", row:0, rowSpan:2, align:"right" },
{ id: "winterAvgBodLowRainfall", title: "청천시 유입BOD\n(mg/L)", row:1, align:"right", widthPercent: 8 },
{ id: "rdiiValue", title: "RDII추정", row:0, rowSpan:2, align:"right", widthPercent: 6 },
{ id: "infoRnDay", title: "RDII추정시\n일강수량\n(mm)", row:0, rowSpan:2, align:"right", widthPercent: 6 },
{ id: "rainCalInflAmnt", title: "강우시\n총 추정유입량\n(m³/일)", row:0, rowSpan:2, align:"right", widthPercent: 6 },
{ id: "properYn", title: "적정여부", row:0, rowSpan:2, widthPercent: 6 },
];
const rdiList:RdiProps[] = [
@@ -153,7 +173,6 @@ const fetchRdiList = async (pageNo: number, pageSize: number, searchYear: string
try{
const tailStr = partCd ? '/'+ partCd + '/' + nameCd + '/' + fcltCpct + '/' + operationValue + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : '';
const url = '/rdii/list/' + pageNo + '/' + pageSize + '/' + searchYear + tailStr;
console.log(url);
const res = await getFetch('fo', url);
return { data: res.data, count: res.count }
}catch(error){
@@ -207,11 +226,6 @@ export const rdiInitState: RdiType = {
const dataFormSetting=(item : RdiProps)=> {
DataForm({ type: 'float0', column: 'fctCpc', item: item as unknown as Record<string, unknown> });
DataForm({ type: 'float1', column: 'summerMinBodValue', item: item as unknown as Record<string, unknown>});
DataForm({ type: 'float1', column: 'winterAvgBodLowRainfall', item: item as unknown as Record<string, unknown>});
DataForm({ type: 'float1', column: 'rdiiValue', item: item as unknown as Record<string, unknown>});
DataForm({ type: 'float1', column: 'infoRnDay', item: item as unknown as Record<string, unknown>});
DataForm({ type: 'float0', column: 'inflAmnt', item: item as unknown as Record<string, unknown>});
}
// Add type definitions for state setter function
@@ -232,9 +246,31 @@ export const rdiReducer:(set:SetStateFunction)=>RdiActions=(set: SetStateFunctio
const res = await fetchRdiList(pageNo, pageSize, searchYear, partCd, nameCd, fcltCpct, operationValue, fcltyNm);
const data = res.data;
const excelDownList: ExcelType[] = [];
const reData = await Promise.all(data.map(async (item: RdiProps) => {
const bscFctCd = item.bscFctCd;
const res2 = await getFetch('fo', '/fclt/flow/' + bscFctCd + '/' + searchYear) as FlowResponse;
const calData = CalcRainEffect(res2.data, 'SUNNY');
let avgChungcunSumFlow = 0;
let chungcunSumFlow = 0;
const rtnData = data.map((item: RdiProps) => {
calData.forEach((flowItem: any) => {
chungcunSumFlow += flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0;
/* if(flowItem.msrDt.substring(4,6) ==='06' || flowItem.msrDt.substring(4,6) ==='07' || flowItem.msrDt.substring(4,6) ==='08'){
sumSummerChungcunDay += 1;
sumSummerChungcunFlow += flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0;
}else if(flowItem.msrDt.substring(4,6) ==='01' || flowItem.msrDt.substring(4,6) ==='02'){
sumWinterChungcunDay += 1;
sumWinterChungcunFlow += flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0;
} */
});
avgChungcunSumFlow = chungcunSumFlow&&chungcunSumFlow>0?chungcunSumFlow / calData.length : 0;
item.chungchunFlow = avgChungcunSumFlow;
item.rainCalInflAmnt = Number(avgChungcunSumFlow) + Number(item.rdiiValue);
return item;
}));
const excelDownList: ExcelType[] = [];
const rtnData = reData.map((item: RdiProps) => {
return {
...item,
sido: item.lclgvrnmntNm.split(' ')[0]?.toString() || '',
@@ -242,44 +278,100 @@ export const rdiReducer:(set:SetStateFunction)=>RdiActions=(set: SetStateFunctio
inflAmnt: item.inflAmnt?Number(item.inflAmnt).toFixed(1): ''
}
})
// 청천히 동절기 유입bod를 새로 구하기 위해서 재 호출
for (const item of rtnData) {
const fcltyCd = item.bscFctCd;
let winterInflBod = 0;
const res: any = await fetchFacilityWaterQltyListHist(searchYear, fcltyCd);
let rtnWinterInflBod = 0;
let rtnSummerBodInfl = 0;
let rtnSummerBod = 0;
let rtnRdiValue = 0;
let rtnRdiRain = 0;
let chungchunFlow = 0;
if (res?.data) {
const clone = (arr: any[]) => arr?.map(v => ({ ...v })) ?? [];
const rtnWqltData = res.data.wqltObjs;
rtnWqltData.forEach((dataItem: any) => {
dataItem.rainEffectDay = 0;
});
const wqltDataTot = CalcRainEffect(clone(rtnWqltData));
const wqltDataSunny = CalcRainEffect(clone(rtnWqltData), 'SUNNY');
calRainEffectDay(rtnWqltData, 'SUNNY');
let chungchunInfl = 0;
let chungchunCnt = 0;
let minSummerBod = 99999999;
let minSummerBodInfl = 99999999;
let winterCnt = 0;
let winterBodSunny = 0;
let rdiRain = 0;
const summerMonth = ['06', '07', '08'];
const winterMonth = ['01', '02'];
const rtnWqltWinterData = rtnWqltData.filter((dataItem: any) =>
(dataItem.msrDt.substring(4, 6) === '01' ||
dataItem.msrDt.substring(4, 6) === '02') &&
dataItem.rainEffectDay == 0
);
wqltDataTot.forEach(item2 => {
if(item2.rainEffectDay == 0){
chungchunCnt ++;
chungchunInfl += Number(item2.inflAmnt);
}
rtnWqltWinterData.forEach((dataItem: any) => {
winterInflBod += dataItem.inflAssctBfrWqltBod
? Number(dataItem.inflAssctBfrWqltBod)
: 0;
if(summerMonth.includes(item2.msrDt.toString().replaceAll('-','').substring(4,6))){
if(Number(item2.infoRnDay)>=3){
const inflBod = Number(item2.inflAssctBfrWqltBod);
const infl = Number(item2.inflAmnt);
const rain = Number(item2.infoRnDay);
if(inflBod < minSummerBod){
minSummerBodInfl = infl;
minSummerBod = inflBod;
rdiRain = rain;
}
}
}
});
if (rtnWqltWinterData.length > 0) {
winterInflBod = winterInflBod / rtnWqltWinterData.length;
}
wqltDataSunny.filter(item=>winterMonth.includes(item.msrDt.toString().replaceAll('-','').substring(4,6))).forEach(item2 => {
winterBodSunny += Number(item2.inflAssctBfrWqltBod);
winterCnt += 1;
});
minSummerBod = minSummerBod === 99999999 ? 0 : minSummerBod;
minSummerBodInfl = minSummerBodInfl === 99999999 ? 0 : minSummerBodInfl;
const roundMinSummerBodInfl = Number(roundNumber(minSummerBodInfl, 0).toString().replaceAll(',',''));
const roundMinSummerBod = Number(roundNumber(minSummerBod, 1).toString().replaceAll(',',''));
const roundWinterBodSunny = Number(roundNumber(winterBodSunny, 1).toString().replaceAll(',',''));
console.log('bsccd : ', item.bscFctCd);
console.log('roundMinSummerBodInfl : ',roundMinSummerBodInfl);
console.log('roundMinSummerBod : ',roundMinSummerBod);
console.log('roundWinterBodSunny : ',roundWinterBodSunny);
const winterBodAvg = Number(roundNumber((roundWinterBodSunny / winterCnt), 1).toString().replaceAll(',',''));
// 하절기(6~8월) 중 최저 유입 BOD일때 유입유량 x ((동절기 청천시 유입BOD - 하절기(6~8월) 중 최저 유입BOD) / (동절기 청천시 유입BOD))
const winMinusSum = winterBodAvg - roundMinSummerBod;
const rdiValue = winMinusSum===0 ? 0 : roundMinSummerBodInfl * (winMinusSum / winterBodAvg );
rtnWinterInflBod = winterBodAvg;
rtnSummerBodInfl = minSummerBodInfl;
rtnSummerBod = minSummerBod;
rtnRdiValue = rdiValue;
rtnRdiRain = rdiRain;
chungchunFlow = chungchunInfl == 0? 0 : chungchunInfl / chungchunCnt;
}
item.winterAvgBodLowRainfall = winterInflBod;
item.summerMinBodValue = roundNumber(rtnSummerBod,1);
item.inflAmnt = roundNumber(rtnSummerBodInfl.toString(), 0);
item.winterAvgBodLowRainfall = roundNumber(rtnWinterInflBod, 1);
item.rdiiValue = roundNumber(rtnRdiValue, 0);
item.infoRnDay = roundNumber(rtnRdiRain, 0);
item.chungchunFlow = roundNumber(chungchunFlow, 0);
item.rainCalInflAmnt = roundNumber(Number(item.chungchunFlow.toString().replaceAll(',','')) + Number(item.rdiiValue.toString().replaceAll(',','')), 0);
item.properYn = Number(item.rainCalInflAmnt.toString().replaceAll(',','')) > Number(item.fctCpc.toString().replaceAll(',','')) ? '초과유입' : '적정';
}
rtnData.forEach((item: RdiProps) => {
dataFormSetting(item)
dataFormSetting(item);
})
if(pageSize>5000){
@@ -294,12 +386,15 @@ export const rdiReducer:(set:SetStateFunction)=>RdiActions=(set: SetStateFunctio
시도: item.sido,
시군구: item.sigungo,
주소: item.daddr,
시설용량: item.fctCpc,
하절기강우일최저유입BOD: item.summerMinBodValue,
하절기최저유입BOD유입유량: item.inflAmnt,
동절기청천시유입BOD: item.winterAvgBodLowRainfall,
RDII추정 : item.rdiiValue,
RDII추정시일강수량 : item.infoRnDay,
"시설용량(m³/일)": item.fctCpc,
"청천시유입하수량(m³/일)": item.chungchunFlow,
"하절기강우일최저유입BOD(mg/L)": item.summerMinBodValue,
"하절기최저유입BOD유입유량(m³/일)": item.inflAmnt,
"동절기청천시유입BOD(mg/L)": item.winterAvgBodLowRainfall,
"RDII추정": item.rdiiValue,
"RDII추정시일강수량(mm)": item.infoRnDay,
"강우시총추정유입량(m³/일)": item.rainCalInflAmnt,
적정여부: item.properYn,
});
});
}
+50 -86
View File
@@ -1,6 +1,8 @@
import DataForm from "@/app/components/common/DataForm";
import type { TableUpperProps } from "../dashboard";
import { getFetch } from "@/app/components/api";
import CalcRainEffect from "@/app/components/common/CalcRainEffect";
import { OSU_PERCENT } from "../common";
export type { TableUpperProps };
/**====================================
* Store - 타입
@@ -50,61 +52,61 @@ export interface ExcelType {
시군구: string,
시설명: string,
주소: string,
시설용량: number,
물사용량: number | '',
오수전환율: number | '',
오수발생량추정: number | '',
연간하수유입량: number | '',
청천시하수유입량: number | '',
"시설용량(m³/일)": number,
"물사용량(m³/일)": number | '',
"오수전환율(%)": number | '',
"오수발생량추정(m³/일)": number | '',
"연간하수유입량(m³/일)": number | '',
"청천시하수유입량(m³/일)": number | '',
}
// 리스트 헤더
const upHeadList1:TableUpperProps[] = [
{ id: "A", title: "행정구역", row:0, colSpan:2 },
{ id: "sidoNm", title: "시도", upName:"upChangeRe", upSequnce:1, row:1 },
{ id: "sggNm", title: "시군구", upName:"upChangeRe",upSequnce:2, row:1 },
{ id: "bscFctNm", title: "시설명", row:0, rowSpan:2 },
{ id: "sidoNm", title: "시도", row:1, widthPercent: 8 },
{ id: "sggNm", title: "시군구", row:1, widthPercent: 8 },
{ id: "bscFctNm", title: "시설명", row:0, rowSpan:2, widthPercent: 8 },
{ id: "daddr", title: "주소", row:0, rowSpan:2 },
{ id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2 },
{ id: "waterUsage", title: "물사용량(m³/일)", align:"right", row:0, rowSpan:2 },
{ id: "swageChangePercent", title: "오수전환율\n(%)", align:"right", row:0, rowSpan:2 },
{ id: "estimationSewage", title: "오수발생량 추정\n(m³/일)", align:"right", row:0, rowSpan:2 },
{ id: "sewageInputYear", title: "연간 하수유입량\n(m³/일)", align:"right", row:0, rowSpan:2 },
{ id: "sewageInputChungchun", title: "청천시 하수유입량\n(m³/일)", align:"right", row:0, rowSpan:2 },
{ id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 8 },
{ id: "waterUsage", title: "물사용량(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 8 },
{ id: "swageChangePercent", title: "오수전환율\n(%)", align:"right", row:0, rowSpan:2, widthPercent: 8 },
{ id: "estimationSewage", title: "오수발생량 추정\n(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 8 },
{ id: "sewageInputYear", title: "연간 하수유입량\n(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 8 },
{ id: "sewageInputChungchun", title: "청천시 하수유입량\n(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 8 },
];
const upHeadList2:TableUpperProps[] = [
{ id: "A", title: "유역", row:0, colSpan:3 },
{ id: "rvbsn", title: "권역", upName:"upChangeRe", upSequnce:1, row:1 },
{ id: "lgbsn", title: "단위유역", upName:"upChangeRe", upSequnce:2, row:1 },
{ id: "mdmbsn", title: "중권역", upName:"upChangeRe", upSequnce:3, row:1 },
{ id: "bscFctNm", title: "시설명", row:0, rowSpan:2 },
{ id: "rvbsn", title: "권역", row:1, widthPercent: 6 },
{ id: "lgbsn", title: "단위유역", row:1, widthPercent: 6 },
{ id: "mdmbsn", title: "중권역", row:1, widthPercent: 6 },
{ id: "bscFctNm", title: "시설명", row:0, rowSpan:2, widthPercent: 8 },
{ id: "daddr", title: "주소", row:0, rowSpan:2 },
{ id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2 },
{ id: "waterUsage", title: "물사용량(m³/일)", align:"right", row:0, rowSpan:2 },
{ id: "swageChangePercent", title: "오수전환율", align:"right", row:0, rowSpan:2 },
{ id: "estimationSewage", title: "오수발생량 추정\n(m³/일)", align:"right", row:0, rowSpan:2 },
{ id: "sewageInputYear", title: "연간 하수유입량\n(m³/일)", align:"right", row:0, rowSpan:2 },
{ id: "sewageInputChungchun", title: "청천시 하수유입량\n(m³/일)", align:"right", row:0, rowSpan:2 },
{ id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 8 },
{ id: "waterUsage", title: "물사용량(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 8 },
{ id: "swageChangePercent", title: "오수전환율", align:"right", row:0, rowSpan:2, widthPercent: 8 },
{ id: "estimationSewage", title: "오수발생량 추정\n(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 8 },
{ id: "sewageInputYear", title: "연간 하수유입량\n(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 8 },
{ id: "sewageInputChungchun", title: "청천시 하수유입량\n(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 8 },
];
const upHeadList3:TableUpperProps[] = [
{ id: "A", title: "유역", row:0, colSpan:3 },
{ id: "rvbsn", title: "권역", upName:"upChangeRe1", upSequnce:1, row:1 },
{ id: "lgbsn", title: "단위유역", upName:"upChangeRe1", upSequnce:2, row:1 },
{ id: "mdmbsn", title: "중권역", upName:"upChangeRe1", upSequnce:3, row:1 },
{ id: "rgnNm", title: "환경청", row:0, rowSpan:2 },
{ id: "rvbsn", title: "권역", row:1, widthPercent: 5 },
{ id: "lgbsn", title: "단위유역", row:1, widthPercent: 5 },
{ id: "mdmbsn", title: "중권역", row:1, widthPercent: 5 },
{ id: "rgnNm", title: "환경청", row:0, rowSpan:2, widthPercent: 8 },
{ id: "B", title: "행정구역", row:0, colSpan:2 },
{ id: "sidoNm", title: "시도", upName:"upChangeRe2", upSequnce:1, row:1 },
{ id: "sggNm", title: "시군구", upName:"upChangeRe2",upSequnce:2, row:1 },
{ id: "bscFctNm", title: "시설명", row:0, rowSpan:2 },
{ id: "sidoNm", title: "시도", row:1, widthPercent: 6 },
{ id: "sggNm", title: "시군구", row:1, widthPercent: 6 },
{ id: "bscFctNm", title: "시설명", row:0, rowSpan:2, widthPercent: 8 },
{ id: "daddr", title: "주소", row:0, rowSpan:2 },
{ id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2 },
{ id: "waterUsage", title: "물사용량(m³/일)", align:"right", row:0, rowSpan:2 },
{ id: "swageChangePercent", title: "오수전환율", align:"right", row:0, rowSpan:2 },
{ id: "estimationSewage", title: "오수발생량 추정\n(m³/일)", align:"right", row:0, rowSpan:2 },
{ id: "sewageInputYear", title: "연간 하수유입량\n(m³/일)", align:"right", row:0, rowSpan:2 },
{ id: "sewageInputChungchun", title: "청천시 하수유입량\n(m³/일)", align:"right", row:0, rowSpan:2 },
{ id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 6 },
{ id: "waterUsage", title: "물사용량(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 6 },
{ id: "swageChangePercent", title: "오수전환율", align:"right", row:0, rowSpan:2, widthPercent: 6 },
{ id: "estimationSewage", title: "오수발생량 추정\n(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 6 },
{ id: "sewageInputYear", title: "연간 하수유입량\n(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 6 },
{ id: "sewageInputChungchun", title: "청천시 하수유입량\n(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 6 },
];
const upHeadListSewageOccurDetail:TableUpperProps[] = [
@@ -236,47 +238,9 @@ export const sewageOccurReducer:(set:any)=>SewageOccurActions=(set: any) => {
let totWaterUsage = 0;
// 강우영향일 계산 (강우량이 3 초과이면 무조건 강우영향일)
for(let idx = 0; idx < res2.data.length; idx++) {
const item = res2.data[idx];
if(item){
if(item.infoRnDay && Number(item.infoRnDay.toString().trim()) >= 3) {
item.rainEffectDay = 1;
} else {
item.rainEffectDay = 0;
}
}
}
// 이틀 전, 하루 전이 강우영향일(3 이상)인 경우 해당 날도 강우영향일로 설정
for(let idx = 0; idx < res2.data.length; idx++) {
if(res2.data[idx]) {
// 하루 전이 강우영향일(3 이상)인 경우
if(idx > 0 && res2.data[idx-1]?.infoRnDay && Number(res2.data[idx-1]?.infoRnDay.toString().trim()) >= 3) {
res2.data[idx]!.rainEffectDay = 1;
}
// 이틀 전이 강우영향일(3 이상)인 경우
if(idx > 1 && res2.data[idx-2]?.infoRnDay && Number(res2.data[idx-2]?.infoRnDay.toString().trim()) >= 3) {
res2.data[idx]!.rainEffectDay = 1;
}
}
}
for(let idx = 0; idx < res2.data.length; idx++) {
if(res2.data[idx] && res2.data[idx]?.rainEffectDay === 1) {
if(idx > 1){
if(res2.data[idx-1]?.infoRnDay && Number(res2.data[idx]?.infoRnDay) < 3 && Number(res2.data[idx-1]?.infoRnDay.toString().trim()) >= 3) {
res2.data[idx]!.infoRnDay = res2.data[idx-1]!.infoRnDay;
}
}
if(idx > 2){
if(res2.data[idx-2]?.infoRnDay && Number(res2.data[idx]?.infoRnDay) < 3 && Number(res2.data[idx-2]?.infoRnDay.toString().trim()) >= 3) {
res2.data[idx]!.infoRnDay = res2.data[idx-2]!.infoRnDay;
}
}
}
}
const rainEffectData = CalcRainEffect(res2.data);
res2.data.forEach((item: FlowDataItem) => {
rainEffectData.forEach((item: FlowDataItem) => {
if(Number(item.rainEffectDay) === 0){
chungcunSumFlow += Number(item.inflAmnt);
@@ -314,12 +278,12 @@ export const sewageOccurReducer:(set:any)=>SewageOccurActions=(set: any) => {
시도: item.sidoNm,
시군구: item.sggNm,
주소: item.daddr,
시설용량: item.fctCpc,
물사용량: item.waterUsage,
오수전환율: item.swageChangePercent,
오수발생량추정: item.estimationSewage,
연간하수유입량 : item.sewageInputYear,
청천시하수유입량 : item.sewageInputChungchun,
"시설용량(m³/일)": item.fctCpc,
"물사용량(m³/일)": item.waterUsage,
"오수전환율(%)": item.swageChangePercent,
"오수발생량추정(m³/일)": item.estimationSewage,
"연간하수유입량(m³/일)": item.sewageInputYear,
"청천시하수유입량(m³/일)": item.sewageInputChungchun,
});
});
}
@@ -382,8 +346,8 @@ export const sewageOccurReducer:(set:any)=>SewageOccurActions=(set: any) => {
tableData.push({
msrDt: item.yr+'-'+(index+1>=10?String(index+1):'0'+(index+1)),
waterUsage: Math.round(item.usege*1) /1,
swageChangePercent: (Math.round((item.usege/item.usege*0.9) * 100) / 100) * 100,
estimationSewage: Math.round(item.usege*0.9 * 1) / 1
swageChangePercent: (Math.round((item.usege/item.usege*OSU_PERCENT) * 100) / 100) * 100,
estimationSewage: Math.round(item.usege*OSU_PERCENT * 1) / 1
})
if (item.usege > maxWaterUsage) {
maxWaterUsage = item.usege;
+69 -113
View File
@@ -2,6 +2,8 @@ import { getFetch } from "@/app/components/api";
import DataForm from "@/app/components/common/DataForm";
import type { TableUpperProps } from "../dashboard";
import type { ExcelType, UnderWaterInputModalProps, UnderWaterProps } from "./types";
import CalcRainEffect from "@/app/components/common/CalcRainEffect";
import { OSU_PERCENT } from "../common";
export type { TableUpperProps };
// SewageOccurDetailProps 타입을 여기에 정의
@@ -33,47 +35,53 @@ const LabelArray:string[] = ['구분', '시도', '시군구','용량별', '시
// 리스트 헤더
const upHeadList1:TableUpperProps[] = [
{ id: "A", title: "행정구역", row:0, colSpan:2 },
{ id: "sidoNm", title: "시도", upName:"upChangeRe", upSequnce:1, row:1 },
{ id: "sggNm", title: "시군구", upName:"upChangeRe",upSequnce:2, row:1 },
{ id: "bscFctNm", title: "시설명", row:0, rowSpan:2 },
{ id: "sidoNm", title: "시도", row:1, widthPercent: 8 },
{ id: "sggNm", title: "시군구", row:1, widthPercent: 8 },
{ id: "bscFctNm", title: "시설명", row:0, rowSpan:2, widthPercent: 8 },
{ id: "daddr", title: "주소", row:0, rowSpan:2 },
{ id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2 },
{ id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 8 },
{ id: "inflAmnt", title: "연평균유입하수량(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 10 },
{ id: "C", title: "지하수 유입량 추정", align:"right", row:0, colSpan:3 },
{ id: "underWaterInputYear", title: "연간\n(m³/일)", align:"right", row:1 },
{ id: "underWaterInputSummer", title: "하절기\n(m³/일)", align:"right", row:1 },
{ id: "underWaterInputWinter", title: "동절기\n(m³/일)", align:"right", row:1 },
{ id: "underWaterInputYear", title: "연간\n(m³/일)", align:"right", row:1, widthPercent: 8 },
{ id: "underWaterInputSummer", title: "하절기\n(m³/일)", align:"right", row:1, widthPercent: 8 },
{ id: "underWaterInputWinter", title: "동절기\n(m³/일)", align:"right", row:1, widthPercent: 8 },
{ id: "properYn", title: "적정여부", row:0, rowSpan:2, widthPercent: 8 },
];
const upHeadList2:TableUpperProps[] = [
{ id: "A", title: "유역", row:0, colSpan:3 },
{ id: "rvbsn", title: "권역", upName:"upChangeRe", upSequnce:1, row:1 },
{ id: "lgbsn", title: "단위유역", upName:"upChangeRe", upSequnce:2, row:1 },
{ id: "mdmbsn", title: "중권역", upName:"upChangeRe", upSequnce:3, row:1 },
{ id: "bscFctNm", title: "시설명", row:0, rowSpan:2 },
{ id: "rvbsn", title: "권역", row:1, widthPercent: 5 },
{ id: "lgbsn", title: "단위유역", row:1, widthPercent: 5 },
{ id: "mdmbsn", title: "중권역", row:1, widthPercent: 5 },
{ id: "bscFctNm", title: "시설명", row:0, rowSpan:2, widthPercent: 8 },
{ id: "daddr", title: "주소", row:0, rowSpan:2 },
{ id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2 },
{ id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 8 },
{ id: "inflAmnt", title: "연평균유입하수량(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 10 },
{ id: "C", title: "지하수 유입량 추정", align:"right", row:0, colSpan:3 },
{ id: "underWaterInputYear", title: "연간\n(m³/일)", align:"right", row:1 },
{ id: "underWaterInputSummer", title: "하절기\n(m³/일)", align:"right", row:1 },
{ id: "underWaterInputWinter", title: "동절기\n(m³/일)", align:"right", row:1 },
{ id: "underWaterInputYear", title: "연간\n(m³/일)", align:"right", row:1, widthPercent: 8 },
{ id: "underWaterInputSummer", title: "하절기\n(m³/일)", align:"right", row:1, widthPercent: 8 },
{ id: "underWaterInputWinter", title: "동절기\n(m³/일)", align:"right", row:1, widthPercent: 8 },
{ id: "properYn", title: "적정여부", row:0, rowSpan:2, widthPercent: 8 },
];
const upHeadList3:TableUpperProps[] = [
{ id: "A", title: "유역", row:0, colSpan:3 },
{ id: "rvbsn", title: "권역", upName:"upChangeRe1", upSequnce:1, row:1 },
{ id: "lgbsn", title: "단위유역", upName:"upChangeRe1", upSequnce:2, row:1 },
{ id: "mdmbsn", title: "중권역", upName:"upChangeRe1", upSequnce:3, row:1 },
{ id: "rgnNm", title: "환경청", row:0, rowSpan:2 },
{ id: "rvbsn", title: "권역", upName:"upChangeRe1", upSequnce:1, row:1, widthPercent: 5 },
{ id: "lgbsn", title: "단위유역", upName:"upChangeRe1", upSequnce:2, row:1, widthPercent: 5 },
{ id: "mdmbsn", title: "중권역", upName:"upChangeRe1", upSequnce:3, row:1, widthPercent: 5 },
{ id: "rgnNm", title: "환경청", row:0, rowSpan:2, widthPercent: 8 },
{ id: "B", title: "행정구역", row:0, colSpan:2 },
{ id: "sidoNm", title: "시도", upName:"upChangeRe2", upSequnce:1, row:1 },
{ id: "sggNm", title: "시군구", upName:"upChangeRe2",upSequnce:2, row:1 },
{ id: "bscFctNm", title: "시설명", row:0, rowSpan:2 },
{ id: "sidoNm", title: "시도", row:1, widthPercent: 6 },
{ id: "sggNm", title: "시군구", row:1, widthPercent: 6 },
{ id: "bscFctNm", title: "시설명", row:0, rowSpan:2, widthPercent: 8 },
{ id: "daddr", title: "주소", row:0, rowSpan:2 },
{ id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2 },
{ id: "fctCpc", title: "시설용량(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 6 },
{ id: "inflAmnt", title: "연평균유입하수량(m³/일)", align:"right", row:0, rowSpan:2, widthPercent: 10 },
{ id: "C", title: "지하수 유입량 추정", align:"right", row:0, colSpan:3 },
{ id: "underWaterInputYear", title: "연간\n(m³/일)", align:"right", row:1 },
{ id: "underWaterInputSummer", title: "하절기\n(m³/일)", align:"right", row:1 },
{ id: "underWaterInputWinter", title: "동절기\n(m³/일)", align:"right", row:1 },
{ id: "underWaterInputYear", title: "연간\n(m³/일)", align:"right", row:1, widthPercent: 6},
{ id: "underWaterInputSummer", title: "하절기\n(m³/일)", align:"right", row:1, widthPercent: 6 },
{ id: "underWaterInputWinter", title: "동절기\n(m³/일)", align:"right", row:1, widthPercent: 6 },
{ id: "properYn", title: "적정여부", row:0, rowSpan:2, widthPercent: 6 },
];
// 모달
@@ -251,6 +259,7 @@ export const underWaterInitState: UnderWaterType = {
const dataFormSetting=(item : UnderWaterProps)=> {
DataForm({ type: 'float0', column: 'fctCpc', item: item as unknown as Record<string, unknown> });
DataForm({ type: 'float0', column: 'inflAmnt', item: item as unknown as Record<string, unknown> });
DataForm({ type: 'float0', column: 'underWaterInputYear', item: item as unknown as Record<string, unknown>});
DataForm({ type: 'float0', column: 'underWaterInputSummer', item: item as unknown as Record<string, unknown>});
DataForm({ type: 'float0', column: 'underWaterInputWinter', item: item as unknown as Record<string, unknown>});
@@ -258,65 +267,6 @@ const dataFormSetting=(item : UnderWaterProps)=> {
export type UnderWaterStore = UnderWaterType & UnderWaterActions;
/**
*
* @param data
* @param weather ('ALL' | 'SUNNY' | 'RAINY')
* @returns
*/
export const calRainEffectDay = (data: any, weather: string) => {
// 강우영향일 계산 (강우량이 3 이상이면 무조건 강우영향일)
for(let idx = 0; idx < data.length; idx++) {
const item = data[idx];
if(item){
if(item.infoRnDay && Number(item.infoRnDay.toString().trim()) >= 3) {
item.rainEffectDay = 1;
} else {
item.rainEffectDay = 0;
}
}
}
// 이틀 전, 하루 전이 강우영향일(3 이상)인 경우 해당 날도 강우영향일로 설정
for(let idx = 0; idx < data.length; idx++) {
if(data[idx]) {
// 하루 전이 강우영향일(3 이상)인 경우
if(idx > 0 && data[idx-1]?.infoRnDay && Number(data[idx-1]?.infoRnDay.toString().trim()) >= 3) {
data[idx]!.rainEffectDay = 1;
}
// 이틀 전이 강우영향일(3 이상)인 경우
if(idx > 1 && data[idx-2]?.infoRnDay && Number(data[idx-2]?.infoRnDay.toString().trim()) >= 3) {
data[idx]!.rainEffectDay = 1;
}
}
}
for(let idx = 0; idx < data.length; idx++) {
if(data[idx] && data[idx]?.rainEffectDay === 1) {
if(idx > 1){
if(data[idx-1]?.infoRnDay && Number(data[idx]?.infoRnDay) < 3 && Number(data[idx-1]?.infoRnDay.toString().trim()) >= 3) {
data[idx]!.infoRnDay = data[idx-1]!.infoRnDay;
}
}
if(idx > 2){
if(data[idx-2]?.infoRnDay && Number(data[idx]?.infoRnDay) < 3 && Number(data[idx-2]?.infoRnDay.toString().trim()) >= 3) {
data[idx]!.infoRnDay = data[idx-2]!.infoRnDay;
}
}
}
}
let rtnData : FlowDataItem[] = [];
if (weather === 'ALL') {
rtnData = data;
} else if (weather === 'SUNNY') {
rtnData = data.filter((item: FlowDataItem) => item.rainEffectDay === 0);
} else {
rtnData = data.filter((item: FlowDataItem) => item.rainEffectDay === 1);
}
return rtnData;
}
export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterType) => void)=>UnderWaterActions=(set: (fn: (state: UnderWaterType) => UnderWaterType) => void) => {
return {
searchUnderWaterList: async (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => {
@@ -337,7 +287,8 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy
const bscFctCd = item.bscFctCd;
const res2 = await getFetch('fo', '/fclt/flow/' + bscFctCd + '/' + searchYear) as ApiResponse;
const calData = calRainEffectDay(res2.data, 'SUNNY');
const calData = CalcRainEffect(res2.data, 'SUNNY');
let chungcunSumFlow = 0;
let sumSummerChungcunDay = 0;
@@ -357,20 +308,19 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy
sumWinterChungcunFlow += flowItem.inflAmnt && flowItem.inflAmnt !== 'x' ? Number(flowItem.inflAmnt.toString().trim()) : 0;
}
});
const usage = chungcunSumFlow / calData.length;
const summerUsage = sumSummerChungcunFlow / sumSummerChungcunDay;
const winterUsage = sumWinterChungcunFlow / sumWinterChungcunDay;
const usage = chungcunSumFlow&&chungcunSumFlow>0?chungcunSumFlow / calData.length:0;
const summerUsage = sumSummerChungcunFlow?sumSummerChungcunFlow / sumSummerChungcunDay:0;
const winterUsage = sumWinterChungcunFlow?sumWinterChungcunFlow / sumWinterChungcunDay:0;
if(bscFctCd === '11200PB001R') {
//bscFctCd === '11200PB001R') 중랑 - 테스트할 때 코드넣고 해야 보기편해요~
/* if(bscFctCd === '11200PB001R') {
console.log('calData.length : ', calData.length);
console.log('usage : ', usage, 'summerUsage : ', summerUsage, 'winterUsage : ', winterUsage);
}
item.underWaterInputYear = Math.round((usage-(usage*0.65*0.9)) * 1) / 1;
item.underWaterInputSummer = Math.round((summerUsage-(summerUsage*0.65*0.9)) * 1) / 1;
item.underWaterInputWinter = Math.round((winterUsage-(winterUsage*0.65*0.9)) * 1) / 1;
} */
item.underWaterInputYear = Math.round((usage-(usage*0.65*OSU_PERCENT)) * 1) / 1;
item.underWaterInputSummer = Math.round((summerUsage-(summerUsage*0.65*OSU_PERCENT)) * 1) / 1;
item.underWaterInputWinter = Math.round((winterUsage-(winterUsage*0.65*OSU_PERCENT)) * 1) / 1;
item.properYn = Math.round( (Number(usage-(usage*0.65*OSU_PERCENT)) / Number(item.inflAmnt)) * 100 * 1 ) / 1 > 20?'초과유입':'적정';
return item;
}));
@@ -391,11 +341,12 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy
시군구: item.sggNm,
시설명: item.bscFctNm,
주소: item.daddr,
시설용량: item.fctCpc,
연간지하수유입량: item.underWaterInputYear,
하절기지하수유입량: item.underWaterInputSummer,
동절기지하수유입량: item.underWaterInputWinter,
"시설용량(m³/일)": item.fctCpc,
"평균유입하수량(m³/일)": item.inflAmnt,
"연간지하수유입량(m³/일)": item.underWaterInputYear,
"하절기지하수유입량(m³/일)": item.underWaterInputSummer,
"동절기지하수유입량(m³/일)": item.underWaterInputWinter,
적정여부: item.properYn,
});
});
}else{
@@ -425,7 +376,7 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy
const res = await getFetch('fo', '/fclt/flow/' + bscFctCd + '/' + searchYear);
const monthData: SewageOccurDetailProps[] = [];
const calData = calRainEffectDay(res.data, 'SUNNY');
const calData = CalcRainEffect(res.data, 'SUNNY');
let tot = 0;
let cnt = 0;
@@ -456,8 +407,8 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy
tableData.push({
msrDt: item.yr+'-'+(index+1>=10?String(index+1):'0'+(index+1)),
realSewageInput:Math.round(item.usege*1) /1,
sewageOccur:Math.round(item.usege*0.65*0.9 * 1) / 1,
underWaterInput:Math.round((item.usege-(item.usege*0.65*0.9)) * 1) / 1,
sewageOccur:Math.round(item.usege*0.65*OSU_PERCENT * 1) / 1,
underWaterInput:Math.round((item.usege-(item.usege*0.65*OSU_PERCENT)) * 1) / 1,
})
if (item.usege > maxWaterUsage) {
maxWaterUsage = item.usege;
@@ -468,28 +419,33 @@ export const underWaterReducer:(set:(fn: (state: UnderWaterType) => UnderWaterTy
}
});
console.log('tot', tot, 'calData.length', calData.length);
if(monthData.length == 0){
maxWaterUsage = 0;
avgWaterUsage = 0;
minWaterUsage = 0;
}
avgWaterUsage = tot/cnt;
console.log(avgWaterUsage);
const newData= [
{
msrDt: '평균',
realSewageInput:Math.round(avgWaterUsage*1) /1,
sewageOccur:Math.round(avgWaterUsage*0.65*0.9 * 1) / 1,
underWaterInput: Math.round((avgWaterUsage-(avgWaterUsage*0.65*0.9)) * 1) / 1
sewageOccur:Math.round(avgWaterUsage*0.65*OSU_PERCENT * 1) / 1,
underWaterInput: Math.round((avgWaterUsage-(avgWaterUsage*0.65*OSU_PERCENT)) * 1) / 1
//underWaterInput:Math.round((avgWaterUsage-(avgWaterUsage*0.65*0.8)) * 100) / 100,
},
{
msrDt: '최대',
realSewageInput: Math.round(maxWaterUsage*1) /1,
sewageOccur: Math.round(maxWaterUsage*0.65*0.9 * 1) / 1,
underWaterInput: Math.round((maxWaterUsage-(maxWaterUsage*0.65*0.9)) * 1) / 1,
sewageOccur: Math.round(maxWaterUsage*0.65*OSU_PERCENT * 1) / 1,
underWaterInput: Math.round((maxWaterUsage-(maxWaterUsage*0.65*OSU_PERCENT)) * 1) / 1,
},
{
msrDt: '최소',
realSewageInput: Math.round(minWaterUsage*1) /1,
sewageOccur: Math.round(minWaterUsage*0.65*0.9 * 1) / 1,
underWaterInput: Math.round((minWaterUsage-(minWaterUsage*0.65*0.9)) * 1) / 1,
sewageOccur: Math.round(minWaterUsage*0.65*OSU_PERCENT * 1) / 1,
underWaterInput: Math.round((minWaterUsage-(minWaterUsage*0.65*OSU_PERCENT)) * 1) / 1,
},
...tableData
]
+10 -4
View File
@@ -14,6 +14,8 @@ export type UnderWaterProps = {
rvbsn : string,
lgbsn : string,
mdmbsn : string,
inflAmnt : number | '',
properYn : string | '',
}
export interface UnderWaterInterface {
bscFctCd : string,
@@ -30,6 +32,8 @@ export interface UnderWaterInterface {
rvbsn : string,
lgbsn : string,
mdmbsn : string,
inflAmnt : number | '',
properYn : string | '',
}
// 모달
@@ -51,8 +55,10 @@ export interface ExcelType {
시군구: string,
시설명: string,
주소: string,
시설용량: number,
연간지하수유입량: number | '',
하절기지하수유입량: number | '',
동절기지하수유입량: number | '',
"시설용량(m³/일)": number,
"평균유입하수량(m³/일)": number | '',
"연간지하수유입량(m³/일)": number | '',
"하절기지하수유입량(m³/일)": number | '',
"동절기지하수유입량(m³/일)": number | '',
적정여부: string | '',
}
+43 -6
View File
@@ -6,7 +6,7 @@ const CLAIM_NAME = process.env.NEXT_PUBLIC_CLAIM_NAME || "Authorization";
const GEOSERVER_URL = process.env.NEXT_PUBLIC_GEOSERVER_URL || "";
const LX_GEOSERVER_URL = process.env.NEXT_PUBLIC_LX_GEOSERVER_URL || "";
const SEWERAGE_API_URL = process.env.NEXT_PUBLIC_SEWERAGE_API_URL || "";
const serverApiUrl = SERVER_API_CS_URL;
export function middleware(req: NextRequest) {
console.log("Middleware 진입:", req.nextUrl.pathname);
const pathname = req.nextUrl.pathname;
@@ -14,7 +14,7 @@ export function middleware(req: NextRequest) {
if (pathname.startsWith("/server")) {
const queryParams = searchParams.toString();
const newUrl = `${SERVER_API_CS_URL}${pathname.replace("/server", "")}${
const newUrl = `${serverApiUrl}${pathname.replace("/server", "")}${
queryParams ? `?${queryParams}` : ""
}`;
console.log(`[Middleware] Rewriting from '/server' path to: ${newUrl}`);
@@ -76,13 +76,47 @@ export function middleware(req: NextRequest) {
const requestHeaders = new Headers(req.headers);
const token = req.cookies.get(CLAIM_NAME)?.value;
const userId = req.cookies.get(AUTH_USER_ID)?.value;
const newUrl = `${SERVER_API_CS_URL}${pathname}`;
const newUrl = `${serverApiUrl}${pathname}`;
if (token) requestHeaders.set(CLAIM_NAME, token);
if (userId) requestHeaders.set(AUTH_USER_ID, userId);
console.log(
`[Middleware] Rewriting from '/attach-service' path to: ${newUrl}`,
`[Middleware] Rewriting from '/attach-service' path to: ${newUrl}`
);
return NextResponse.rewrite(new URL(newUrl), {
headers: requestHeaders,
});
}
if (pathname.startsWith("/operation-service")) {
const requestHeaders = new Headers(req.headers);
const token = req.cookies.get(CLAIM_NAME)?.value;
const userId = req.cookies.get(AUTH_USER_ID)?.value;
const newUrl = `${serverApiUrl}${pathname}`;
if (token) requestHeaders.set(CLAIM_NAME, token);
if (userId) requestHeaders.set(AUTH_USER_ID, userId);
console.log(
`[Middleware] Rewriting from '/operation-service' path to: ${newUrl}`
);
return NextResponse.rewrite(new URL(newUrl), {
headers: requestHeaders,
});
}
if (pathname.startsWith("/reuse-service")) {
const requestHeaders = new Headers(req.headers);
const token = req.cookies.get(CLAIM_NAME)?.value;
const userId = req.cookies.get(AUTH_USER_ID)?.value;
const newUrl = `${serverApiUrl}${pathname}`;
if (token) requestHeaders.set(CLAIM_NAME, token);
if (userId) requestHeaders.set(AUTH_USER_ID, userId);
console.log(
`[Middleware] Rewriting from '/reuse-service' path to: ${newUrl}`
);
return NextResponse.rewrite(new URL(newUrl), {
headers: requestHeaders,
@@ -94,12 +128,13 @@ export function middleware(req: NextRequest) {
const newUrl = `${SERVER_API_CS_URL}${pathname}`;
console.log(
`[Middleware] Rewriting from '/user-service' path to: ${newUrl}`,
`[Middleware] Rewriting from '/user-service' path to: ${newUrl}`
);
return NextResponse.rewrite(new URL(newUrl), {
headers: requestHeaders,
});
}
if (pathname === "/") {
return NextResponse.redirect(new URL("/pages/dashboard", req.url));
}
@@ -108,11 +143,13 @@ export function middleware(req: NextRequest) {
export const config = {
matcher: [
"/",
"/server/:path*",
"/geoserver/:path*",
"/attach-service/:path*",
"/user-service/:path*",
"/cms-service/:path*",
"/"
"/operation-service/:path*",
"/reuse-service/:path*",
],
};
Binary file not shown.
+3 -2
View File
@@ -8,6 +8,7 @@ NEXT_PUBLIC_PROXY_HOST = http://con.mind-one.co.kr:11302
NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000
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_DC_URL = https://apigateway.apps.rsonesoft.com
NEXT_PUBLIC_NGII_URL = https://map.ngii.go.kr/openapi/Gettile.do?apiKey=04trYP9_xwLAfALjwZ-B8g
NEXT_PUBLIC_SEWERAGE_API_URL=http://con.mind-one.co.kr:11083/sewerage-service/api
NEXT_PUBLIC_DC_URL = https://apigateway.apps.rsonesoft.com
NEXT_PUBLIC_CM_LOGIN_PAGE_URL = http://dev.onasys.co.kr:3000/auth/login
NEXT_PUBLIC_SEWERAGE_API_URL=http://con.mind-one.co.kr:11083
+9 -7
View File
@@ -4,13 +4,15 @@ NEXT_PUBLIC_AUTH_USER_ID = token-id
NEXT_PUBLIC_ACCESS_TOKEN = access-token
NEXT_PUBLIC_REFRESH_TOKEN = refresh-token
NEXT_PUBLIC_PORT = 3002
NEXT_PUBLIC_PROXY_HOST = http://localhost:3002
NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000
# NEXT_PUBLIC_PROXY_HOST = http://localhost:3002
NEXT_PUBLIC_PROXY_HOST = http://sn.onasys.co.kr:3002
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_DC_URL = https://apigateway.apps.rsonesoft.com
NEXT_PUBLIC_NGII_URL = https://map.ngii.go.kr/openapi/Gettile.do?apiKey=04trYP9_xwLAfALjwZ-B8g
NEXT_PUBLIC_SEWERAGE_API_URL=http://con.mind-one.co.kr:11083/sewerage-service/api
#NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.128:8883/sewerage-service/api
#NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.222:8883/sewerage-service/api
#NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.66:8883/sewerage-service/api
NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000
NEXT_PUBLIC_SEWERAGE_API_URL=http://con.mind-one.co.kr:11083
NEXT_PUBLIC_DC_URL = https://apigateway.apps.rsonesoft.com
NEXT_PUBLIC_CM_LOGIN_PAGE_URL = http://dev.onasys.co.kr:3000/auth/login
#NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.128:8883
#NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.222:8883
#NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.66:8883
+6 -5
View File
@@ -4,10 +4,11 @@ NEXT_PUBLIC_AUTH_USER_ID = token-id
NEXT_PUBLIC_ACCESS_TOKEN = access-token
NEXT_PUBLIC_REFRESH_TOKEN = refresh-token
NEXT_PUBLIC_PORT = 3000
NEXT_PUBLIC_PROXY_HOST = https://sn.hasuon.or.kr
NEXT_PUBLIC_SERVER_API_URL = http://apigateway.iipbs-dev.svc.cluster.local:8000
NEXT_PUBLIC_PROXY_HOST = https://lion.hasuon.or.kr
NEXT_PUBLIC_GEOSERVER_URL = http://172.29.143.87:8080/geoserver
NEXT_PUBLIC_LX_GEOSERVER_URL = http://172.29.143.87:8080/geoserver_swl
NEXT_PUBLIC_DC_URL = http://apigateway.iipbs-dev.svc.cluster.local:8000
NEXT_PUBLIC_LX_GEOSERVER_URL = http://172.29.143.87:8080/geoserver_swl
NEXT_PUBLIC_NGII_URL = http://10.98.25.94:18080/openapi/Gettile.do?apiKey=BDE2BEF39DAFEC293AB6730150F222AC
NEXT_PUBLIC_SEWERAGE_API_URL = https://apigateway.hasuon.or.kr/sewerage-service/api
NEXT_PUBLIC_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000
NEXT_PUBLIC_SEWERAGE_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000
NEXT_PUBLIC_DC_URL = http://apigateway.iipbs-was.svc.cluster.local:8000
NEXT_PUBLIC_CM_LOGIN_PAGE_URL = http://dev.onasys.co.kr:3000/auth/login
+14
View File
@@ -0,0 +1,14 @@
NEXT_PUBLIC_SITE_ID = SN
NEXT_PUBLIC_CLAIM_NAME = Authorization
NEXT_PUBLIC_AUTH_USER_ID = token-id
NEXT_PUBLIC_ACCESS_TOKEN = access-token
NEXT_PUBLIC_REFRESH_TOKEN = refresh-token
NEXT_PUBLIC_PORT = 3000
NEXT_PUBLIC_PROXY_HOST = https://sn.hasuon.or.kr
NEXT_PUBLIC_GEOSERVER_URL = http://172.29.143.87:8080/geoserver
NEXT_PUBLIC_LX_GEOSERVER_URL = http://172.29.143.87:8080/geoserver_swl
NEXT_PUBLIC_NGII_URL = http://10.98.25.94:18080/openapi/Gettile.do?apiKey=BDE2BEF39DAFEC293AB6730150F222AC
NEXT_PUBLIC_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000
NEXT_PUBLIC_SEWERAGE_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000
NEXT_PUBLIC_DC_URL = http://apigateway.iipbs-was.svc.cluster.local:8000
NEXT_PUBLIC_CM_LOGIN_PAGE_URL = http://dev.onasys.co.kr:3000/auth/login
+13
View File
@@ -1,3 +1,16 @@
/**
* ➡️ 경로 : 하수관망도 모든 페이지
*
* 📄 Map Layout
* Next.js App Router (app/) 기반 맵 레이아웃 컴포넌트
*
* - 메뉴 클릭 이벤트 처리 및 라우팅
* - 현재 메뉴 정보 Zustand를 통한 상태 관리
* - 시도/시군구/사업 구분/사업 유형 데이터 초기 로드
* - NoFooterLayout을 통한 공통 레이아웃 적용
* - QueryClient를 통한 데이터 캐싱 및 관리
* - 경로 변경 시 메뉴 정보 동기화
*/
"use client";
import React, { useEffect } from 'react';
@@ -1,10 +1,25 @@
/**
* ➡️ 경로 : 하수관망도 메인 페이지 (시설물 클릭) - 오른쪽 팝업창 (하수관로)
*
* 📄 MsSwagePpl
* 하수관로 정보 컴포넌트
*
* - 하수관로의 자체입력정보 표시 및 편집 기능
* - 보수 및 갱신, 청소 및 준설, 점검 및 진단 데이터 조회 및 표시
* - VerticalTable을 통한 입력 폼 렌더링
* - InputSection을 통한 운영 데이터 관리
* - 저장 버튼을 통한 데이터 저장 기능
*
* 🔗 사용 API
* - 시설별 운영 정보 조회: GET /api/v1/bizInfo/bizByFclt (sewerage-service)
*/
'use client'
import { VerticalTable } from '@/components/ui/verticalTable';
import React, { useState, useEffect } from 'react'
import InputSection from '../InputSection';
import { handleInputChange } from '../common';
import { getData } from "@/components/lib/api";
import useStore from '../../../../store/useStore';
import useStore from '@/store/useStore';
// 하수관로
const inputColumn = [
@@ -88,9 +103,6 @@ const MsSwagePpl = ({ featureData, onSaveClick }: { featureData: any, onSaveClic
setInspectionData(inspectionArr);
setCleaningData(cleaningArr);
setRepairData(repairArr);
console.log('inspectionArr', inspectionArr);
console.log('cleaningArr', cleaningArr);
console.log('repairArr', repairArr);
};
fetchAll();
}, [featureData]);
@@ -1,7 +1,21 @@
// 우수토실
/**
* ➡️ 경로 : 하수관망도 메인 페이지 (시설물 클릭) - 오른쪽 팝업창 (우수토실)
*
* 📄 Ssc
* 우수토실 정보 컴포넌트
*
* - 우수토실의 자체입력정보 표시 및 편집 기능
* - 중점우수토실 운영정보 모달 표시 (강우/측정 정보, 수량/수질측정 정보)
* - VerticalTable을 통한 입력 폼 렌더링
* - 저장 버튼을 통한 데이터 저장 기능
*
* 🔗 사용 API
* - 위경도로 강우시 미처리 하수 목록 조회: GET /api/v1/onsemiro/getSwgRainsByGeomety (sewerage-service)
* - 강우시 월류 하수 관리 모니터링 조회: GET /api/v1/onsemiro/swgRain/{adstDstrCd}/{manageNo}/mntrngs (sewerage-service)
*/
import { UiModal, UiTable } from '@common/business_components/ui';
import { Button, TableHead, TableRow } from '@common/components/ui';
import React, { useState, useEffect, useCallback } from 'react';
import React, { useState, useEffect } from 'react';
import { untrtSwgRainCol3, untrtSwgRainCol4, untrtSwgRainCol5 } from '../common/table';
import { VerticalTable } from '@/components/ui/verticalTable';
import { getData } from "@/components/lib/api";
@@ -34,8 +48,6 @@ const Ssc = ({ featureData, isMainSsc, chmbrXcnts, chmbrYdnts, onSaveClick }: {
const [isResetDetailPage, setIsResetDetailPage] = useState<boolean>(true);
const [isResetSelection, setIsResetSelection] = useState<boolean>(false);
console.log('featureData', featureData);
// 강우, 측정 정보 API 호출 함수
const fetchRainMeasureData = async (chmbrXcnts: string, chmbrYdnts: string) => {
setIsResetDetailPage(true);
@@ -53,13 +65,8 @@ const Ssc = ({ featureData, isMainSsc, chmbrXcnts, chmbrYdnts, onSaveClick }: {
size: '3',
});
console.log('queryParams', queryParams.toString());
console.log(`추가 데이터 API 호출 시작: v1/onsemiro/getSwgRainsByGeomety?${queryParams.toString()}`);
const result = await getData(`v1/onsemiro/getSwgRainsByGeomety?${queryParams.toString()}`);
console.log('추가 데이터 API 호출 성공:', result);
const processedDataArray: any[] = result.content.map((data: any) => {
// 🎯 formatDisplayData로 기본 포맷팅 적용
const formattedItem = formatDisplayData(data);
@@ -92,12 +99,8 @@ const Ssc = ({ featureData, isMainSsc, chmbrXcnts, chmbrYdnts, onSaveClick }: {
size: '3',
});
console.log(`SSC 추가 데이터 API 호출 시작: v1/onsemiro/swgRain/${adstDstrCd}/${manageNo}/mntrngs?${queryParams.toString()}`);
const result = await getData(`v1/onsemiro/swgRain/${adstDstrCd}/${manageNo}/mntrngs?${queryParams.toString()}`);
console.log('SSC 추가 데이터 API 호출 성공:', result);
// 각 아이템 전처리
const processedDataArray = result.content.map((data: any) => {
// 기본 포맷팅 적용
@@ -107,8 +110,6 @@ const Ssc = ({ featureData, isMainSsc, chmbrXcnts, chmbrYdnts, onSaveClick }: {
};
});
console.log('processedDataArray', processedDataArray);
setMntrngsData(processedDataArray);
setTotalDetailCount(result?.totalElements || 0);
} catch (error) {
@@ -1,3 +1,13 @@
/**
* ➡️ 경로 : 하수관망도 메인 페이지 (시설물 클릭) - 오른쪽 팝업창 (하수처리시설)
*
* 📄 SwtrmtFclt
* 하수처리시설 정보 컴포넌트
*
* - 하수처리시설의 디지털 자료관 연계 정보 표시
* - VerticalTable을 통한 테이블 렌더링
* - 조회 버튼을 통한 모달 표시 및 ReportTab 연동
*/
'use client'
import React, { useState } from 'react'
import { VerticalTable } from '@/components/ui/verticalTable';
@@ -84,7 +84,6 @@ const selectAplcnYms = async(gubun:string) => { // 상수사용월
const queryString = '';
const result = await getData(`v1/${gubun}/aplcnYm${queryString ? `?${queryString}` : ''}`);
if (result && result.length > 0) {
console.log("selectAplcnYms", result);
return getOptionsAplcnYm(result);
}
} catch (error) {
@@ -119,7 +118,6 @@ export const selectInftwtAnls = async(aplcnYm:string) => { // 침입수분석
const queryString = aplcnYm ? `aplcnYmFrom=${aplcnYm}&aplcnYmTo=${aplcnYm}` : '';
const result = await getData(`v1/inftwtAnls${queryString ? `?${queryString}` : ''}`);
if (result && result.numberOfElements > 0) {
console.log("selectInftwtAnls", result.content);
return result.content;
}
} catch (error) {
@@ -141,7 +139,6 @@ export const selectInftwtAnlsRslt = async(inftwtAnlsSn:number, pplMngNo:string)
}
const result = await getData(`v1/inftwtAnlsRslt/ppl/${inftwtAnlsSn}/${pplMngNo}`);
if (result && result.numberOfElements > 0) {
console.log("selectInftwtAnlsRslt", result.content);
return result.content;
}
} catch (error) {
@@ -163,7 +160,6 @@ export const selectOilq = async(inftwtAnlsSn:number, pplMngNo:string) => { //
}
const result = await getData(`v1/inftwtAnlsRslt/oilqPpl/${inftwtAnlsSn}/${pplMngNo}`);
if (result && result.numberOfElements > 0) {
console.log("selectOilq", result.content);
return result.content;
}
} catch (error) {
@@ -178,7 +174,6 @@ export const selectPplInftwtQty = async(inftwtAnlsSn:number, pplMngNo:string) =>
}
const result = await getData(`v1/inftwtAnlsRslt/pplInftwtQty/${inftwtAnlsSn}/${pplMngNo}`);
if (result.length > 0) {
console.log("selectPplInftwtQty", result);
return result[0].avg_day_flow;
} else {
return 0; // 데이터가 없을 경우 0 반환
@@ -196,7 +191,6 @@ export const selectPplRdiiQty = async(rainInfwtAnlsSn:number, pplMngNo:string) =
}
const result = await getData(`v1/rdiiAnlsRslt/pplRdiiQty/${rainInfwtAnlsSn}/${pplMngNo}`);
if (result?.sustaintime > 0) {
console.log("selectPplRdiiQty", result);
return result;
}
} catch (error) {
@@ -218,7 +212,6 @@ export const selectRdiiAnls = async(aplcnYm:string) => { // 침입수분석
const queryString = aplcnYm ? `aplcnYmFrom=${aplcnYm}&aplcnYmTo=${aplcnYm}` : '';
const result = await getData(`v1/rdiiAnls${queryString ? `?${queryString}` : ''}`);
if (result && result.numberOfElements > 0) {
console.log("selectRdiiAnls", result.content);
return result.content;
}
} catch (error) {
@@ -262,7 +255,6 @@ export const selectRainData = async(rainInfwtAnlsSn:number) => { // 강우데이
}
const result = await getData(`v1/rdiiAnlsRslt/rainData/${rainInfwtAnlsSn}`);
if (result && result.numberOfElements > 0) {
console.log("selectRainData", result.content);
return result.content;
}
} catch (error) {
@@ -63,7 +63,6 @@ const InfilChart = ({ pplMngNo }: ModalOpenProp) => {
// 상수사용월 변경 핸들러
const handleAplcnYmChange = async (val: string | number) => {
const selectedValue = String(val);
console.log("선택된 상수사용월:", selectedValue);
setSelectedAplcnYm(selectedValue);
@@ -1,3 +1,26 @@
/**
* ➡️ 경로 : 하수관망도 메인 페이지 (시설물 클릭) - 오른쪽 팝업창
*
* 📄 FeatureClickEventPopup
* 시설물(피처) 클릭시 오른쪽 팝업창 컴포넌트
*
* - 지도 시설물(피처) 클릭 시 팝업 표시 및 데이터 로딩
* - 레이어 유형에 따른 동적 테이블 및 헤드리스트 설정
* - 자체입력정보 조회 및 저장 기능 (하수관로, 우수토실, 하수펌프장, 하수맨홀)
* - 코드 매핑 및 데이터 포맷팅 처리
* - 상류관로 검색, 침입수/RDII 분석 차트 표시
* - 모달을 통한 저장 확인 및 API 연동
*
* 🔗 사용 API
* - 하수관로 자체입력정보 조회: GET /api/v1/fcltppl/{fcltMngNo}/{mngInstCd} (sewerage-service)
* - 우수토실 자체입력정보 조회: GET /api/v1/fcltstofcbr/{fcltMngNo}/{mngInstCd} (sewerage-service)
* - 하수펌프장 자체입력정보 조회: GET /api/v1/fcltpump/{fcltMngNo}/{mngInstCd} (sewerage-service)
* - 하수맨홀 자체입력정보 조회: GET /api/v1/fcltmhl/{fcltMngNo}/{mngInstCd} (sewerage-service)
* - 하수관로 자체입력정보 저장: POST /api/v1/fcltppl (sewerage-service)
* - 우수토실 자체입력정보 저장: POST /api/v1/fcltstofcbr (sewerage-service)
* - 하수펌프장 자체입력정보 저장: POST /api/v1/fcltpump (sewerage-service)
* - 하수맨홀 자체입력정보 저장: POST /api/v1/fcltmhl (sewerage-service)
*/
'use client'
import { getData, postData } from "@/components/lib/api";
import Modal from "@/components/ui/modal";
@@ -75,7 +98,6 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
if (featureData['ol_uid']) {
// Gis 레이어 클릭 이벤트
setIsClicked(true);
console.log('gis data', featureData.values_);
const lyrTyNm = featureData.id_.split('.')[0];
switch (lyrTyNm) {
@@ -139,7 +161,6 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
else {
// SearchModal 클릭 이벤트
setIsClicked(false);
console.log('SearchModal data', featureData);
const lyrTyNm = featureData.lyrTypeNm;
switch (lyrTyNm) {
@@ -158,12 +179,10 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
case 'tb_ms_swage_pmstn': {
const drtwPumpCode = DRTW_SEWAGE_PUMP_USE_CODES.find(code => code.text === '오수펌프장');
if (drtwPumpCode && featureData.usgCd.trim() === drtwPumpCode.val) {
console.log('오수펌프장');
setIsDrtwSewagePump(false);
setHeadlist(ExclnSewagePumpCol2)
}
else {
console.log('빗물펌프장');
setIsDrtwSewagePump(true);
setHeadlist(DrtwSewagePumpCol2)
}
@@ -299,9 +318,6 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
const result = await getData(apiEndpoint);
if (result) {
console.log('API 데이터 로드 성공:', result);
// ✅ codeMapper 사용하여 API 결과도 변환
const processedApiData = codeMapper({
layerName: selectedLayerName,
data: { ...result, ...tableData }
@@ -381,12 +397,9 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
bodyData.prrtymngYn = 'N';
}
}
console.log('bodyData', bodyData);
console.log('apiEndpoint', apiEndpoint);
try {
result = await postData(apiEndpoint, bodyData);
console.log('result', result);
if (result) {
alert('저장되었습니다');
@@ -1,3 +1,13 @@
/**
* ➡️ 경로 : 하수관망도 메인 페이지 (시설물 클릭) - 오른쪽 팝업창 (하수펌프장)
*
* 📄 sewagePump
* 하수펌프장 정보 컴포넌트
*
* - 빗물펌프장 및 오수펌프장 구분에 따른 자체 입력 정보 표시 및 편집 기능
* - VerticalTable을 통한 입력 폼 렌더링
* - 저장 버튼을 통한 데이터 저장 기능
*/
import { VerticalTable } from '@/components/ui/verticalTable';
import React, { useState, useEffect } from 'react'
// 빗물펌프장 자체 입력 정보
@@ -12,7 +22,7 @@ const drtwInputColumn = [
{ id: "mltvDtdvNm", title: "처리분구", type: "input" },
]
// 하수펌프장
const sewagePump = ({ featureData, isDrtwSewagePump, onSaveClick }: { featureData: any, isDrtwSewagePump?: boolean, onSaveClick?: () => void }) => {
const [formData, setFormData] = useState<any>({});
@@ -1,11 +1,24 @@
// 하수맨홀
/**
* ➡️ 경로 : 하수관망도 메인 페이지 (시설물 클릭) - 오른쪽 팝업창 (하수맨홀)
*
* 📄 Smh
* 하수맨홀 정보 컴포넌트
*
* - 하수맨홀의 자체입력정보 표시 및 편집 기능
* - VerticalTable을 통한 입력 폼 렌더링
* - 상류관로 검색 및 지도 포커스 기능
* - 저장 버튼을 통한 데이터 저장 기능
*
* 🔗 사용 API
* - 상류관로 조회: GET /api/v1/fcltmhl/upperPpls/{fcltMngNo} (sewerage-service)
*/
import { VerticalTable } from '@/components/ui/verticalTable';
import { useEffect, useState } from 'react';
import GisApp from "@common/business_components/ui/map/lib/gis.core";
// 상류관로 보기 함수 (FeatureClickEventPopup에서 사용)
export async function searchUpperPpls(gisMap: any, fcltMngNo: any) {
const BASE_URL = process.env.NEXT_PUBLIC_SEWERAGE_API_URL || "";
const BASE_URL = "/sewerage-service/api";
const res = await fetch(`${BASE_URL}/v1/fcltmhl/upperPpls/${fcltMngNo}`, {
method: "GET",
});
@@ -1,3 +1,12 @@
/**
* ➡️ 경로 : 하수관망도 메인 페이지 (시설물 클릭) - 오른쪽 팝업창 (빗물펌프)
*
* 📄 StormWaterPump
* 빗물펌프 정보 컴포넌트
*
* - 빗물펌프의 자체입력정보 표시 및 편집 기능
* - VerticalTable을 통한 입력 폼 렌더링
*/
import { VerticalTable } from '@/components/ui/verticalTable';
import React from 'react'
const inputColumn = [
+23 -30
View File
@@ -1,3 +1,20 @@
/**
* ➡️ 경로 : 하수관망도 메인 페이지
*
* 📄 Map Page
* 지도 페이지 컴포넌트
*
* - OpenLayers 기반 GIS 지도 렌더링 및 상호작용
* - 레이어 트리 데이터 관리 및 동적 레이어 표시/숨김
* - 피처 검색 및 선택 기능 (SearchModal, ProcSearchBar)
* - 피처 클릭 이벤트 처리 및 상세 정보 팝업 표시
* - 수심(WaterDepth) 레이어 애니메이션 재생 기능
* - Zustand를 통한 검색 모달 상태 관리
*
* 🔗 사용 API
* - 레이어 설정 조회: GET /api/v1/map/lyrStngs/{lyrGrp} (sewerage-service)
*/
"use client";
import Gis from "@common/business_components/ui/map/Gis";
@@ -8,37 +25,14 @@ import SearchModal from "./searchModal/searchModal";
import FeatureClickEventPopup from "./components/popupComponent/featureClickEventPopup";
import { WaterDepth, WATER_DEPTH_LAYER_TYPES } from "./waterDepth/waterDepth";
import { ProcSearchBar } from "@common/business_components/ui/map/searchBar";
// 타입 정의 추가
export type LyrStngProps = {
lyr_sn: string;
lyr_nm: string;
upper_lyr_sn: string;
drawOrdr: string;
flterSql: string;
gobjTy: string;
lyrTpNm: string;
useYn: string;
minViewSize: string;
iconNm: string;
lblAtrbNm: string;
fontNm: string;
fontIntnColor: string;
fontExtnColor: string;
fontExtnWdth: string;
lnWdth: string;
lnColor: string;
polgnColor: string;
initEprssYn: string;
clickPsblYn: string;
};
import useSearchModalStore from "@/store/useSearchModalStore";
const Map = () => {
const { isSearchModalOpen, setIsSearchModalOpen } = useSearchModalStore();
const [treeData, setTreeData] = useState([]); // 초기값을 객체 또는 null로 설정
const [selectedFeature, setSelectedFeature] = useState(null); // 선택된 피처 상태
const gisMaps = useRef<any | null>(null);
const [isOpen, setIsOpen] = useState(false); // 팝업 열기/닫기 상태
const [isSearchModalOpen, setIsSearchModalOpen] = useState(false); // SearchModal 열림 상태
const [featureData, setFeatureData] = useState(null); // 선택된 피쳐 데이터
const [showWaterDepth, setShowWaterDepth] = useState(false); // WaterDepth 표시 여부
const [isPlaying, setIsPlaying] = useState(false);
@@ -95,7 +89,6 @@ const Map = () => {
});
}
// 3. 피처 선택
if (foundFeature) {
let geometry = foundFeature.getGeometry();
@@ -148,12 +141,12 @@ const Map = () => {
searchView={SearchModal}
detailView={FeatureClickEventPopup}
onFeatureSelect={onFeatureSelect}
setIsOpen={setIsOpen}
setFeatureData={setFeatureData}
featureData={featureData}
setIsSearchModalOpen={setIsSearchModalOpen}
setFeatureData={setFeatureData}
isOpen={isOpen}
setIsOpen={setIsOpen}
isSearchModalOpen={isSearchModalOpen}
setIsSearchModalOpen={setIsSearchModalOpen}
onCheckedLayersChange={handleCheckedLayersChange}
searchBar={<ProcSearchBar gisMaps={gisMaps} facilityTypes={facilityTypes} />}
waterDepth={showWaterDepth ? WaterDepth : undefined}
@@ -1,15 +1,23 @@
/**
* ➡️ 경로 : 하수관망도 메인 페이지 (오른쪽 돋보기 모양 클릭) - 검색 모달 창 내 기본정보 탭
*
* 📄 BasicTab Component
* Next.js App Router (app/) 기반 검색 모달의 기본정보 탭 컴포넌트
*
* - 기본정보 검색을 위한 구분 선택 및 조건 입력 UI 제공
* - 하수관로, 하수처리시설, 하수처리구역, 하수맨홀, 하수펌프장, 우수토실 등 다양한 유형별 컴포넌트 렌더링
* - useSearchModalStore를 통해 상태 관리 및 사용자 상호작용 처리
*/
import React from 'react';
import { YearRangeSelectBox } from '@/components/ui/YearRangeSelectBox';
import { SelectBox } from '@common/business_components/ui';
import { Button, Label } from '@common/components';
import { Label } from '@common/components';
import SwagePpl from './swagePpl';
import SwagePrcsFclt from './swagePrcsFclt';
import SwagePrcsZone from './swagePrcsZone';
import SwageMhl from './swageMhl';
import SwagePmstn from './swagePmstn';
import Stofcbr from './stofcbr';
import { useSearchModal, type SearchModalProps } from './useSearchModal';
import useSearchModalStore from '../../../store/useSearchModalStore';
import useSearchModalStore from '@/store/useSearchModalStore';
// 기본정보 '구분' 선택 목록
@@ -22,7 +30,7 @@ export const BASIC_TYPES = [
{ val: "tb_ms_stofcbr", text: "우수토실" },
];
const BasicTab: React.FC<SearchModalProps> = (props) => {
const BasicTab: React.FC = () => {
const { basicType, setBasicType } = useSearchModalStore();
return (
@@ -45,12 +53,12 @@ const BasicTab: React.FC<SearchModalProps> = (props) => {
</div>
</div>
{/* 조회 조건 */}
{basicType === "tb_ms_swage_ppl" && (<SwagePpl {...props} />)} {/* 하수관로 */}
{basicType === "tb_il_swage_prcs_fclt" && (<SwagePrcsFclt {...props} />)} {/* 하수처리시설 */}
{basicType === "tb_ms_swage_prcs_zone" && (<SwagePrcsZone {...props} />)} {/* 하수처리구역 */}
{basicType === "tb_ms_swage_mhl" && (<SwageMhl {...props} />)} {/* 하수맨홀 */}
{basicType === "tb_ms_swage_pmstn" && (<SwagePmstn {...props} />)} {/* 하수펌프장 */}
{basicType === "tb_ms_stofcbr" && (<Stofcbr {...props} />)} {/* 우수토실 */}
{basicType === "tb_ms_swage_ppl" && (<SwagePpl />)} {/* 하수관로 */}
{basicType === "tb_il_swage_prcs_fclt" && (<SwagePrcsFclt />)} {/* 하수처리시설 */}
{basicType === "tb_ms_swage_prcs_zone" && (<SwagePrcsZone />)} {/* 하수처리구역 */}
{basicType === "tb_ms_swage_mhl" && (<SwageMhl />)} {/* 하수맨홀 */}
{basicType === "tb_ms_swage_pmstn" && (<SwagePmstn />)} {/* 하수펌프장 */}
{basicType === "tb_ms_stofcbr" && (<Stofcbr />)} {/* 우수토실 */}
</div>
);
};

Some files were not shown because too many files have changed in this diff Show More