Merge branch 'iipbs/sn/dev' of https://www.onasys.co.kr:3000/ONAANDALL/frontend into iipbs/sn/dev
This commit is contained in:
@@ -87,7 +87,7 @@ export const useExmnResultMap = (options: Options) => {
|
||||
[gisApp, mapRef],
|
||||
);
|
||||
|
||||
/** 지역 검색값 없이 전체를 요청하고, 선택 진입 context는 위치 이동 범위 조회에만 사용한다. */
|
||||
/** 일반 진입은 전체, 조사관리 지도보기는 선택 사업·처리분구만 조회해 겹친 타 사업 선택을 방지한다. */
|
||||
const loadLayer = useCallback(
|
||||
async (job: ExmnMapJobType, filters: ExmnMapFilters) => {
|
||||
const map = mapRef.current;
|
||||
@@ -109,7 +109,9 @@ export const useExmnResultMap = (options: Options) => {
|
||||
const response = await getExmnMapLayer(
|
||||
job,
|
||||
filters,
|
||||
{},
|
||||
entry.exmnBizId && entry.trtdstId
|
||||
? { exmnBizId: entry.exmnBizId, trtdstId: entry.trtdstId }
|
||||
: {},
|
||||
controller.signal,
|
||||
);
|
||||
if (!active()) return;
|
||||
|
||||
@@ -275,3 +275,8 @@
|
||||
|
||||
- 레이어 API 단위 테스트는 실제 서비스가 호출하는 Repository 메서드와 동일한 메서드를 모킹해야 한다.
|
||||
- 전체 빌드가 장시간 걸리는 환경에서는 변경 파일 정적 검사 후 백엔드 대상 테스트와 로그인 브라우저 회귀를 분리한다.
|
||||
|
||||
|
||||
## 2026-10-19 맨홀 PDF GIS 번호 검증
|
||||
- 188001 테스트 PDF 실제 판독·쪽 추출, PPL/MNHL 첨부 분리, 미첨부·없는 번호·중복 시설·다중/비연속 번호를 검증한다.
|
||||
- 실제 서버에서는 맨홀 첨부 저장 → 상류맨홀 지도 선택 → 맨홀 보고서 1쪽 표시와 관로 회귀를 확인한다. 자동검증/실브라우저 여부는 통합검증결과에 구분한다.
|
||||
|
||||
@@ -678,3 +678,44 @@
|
||||
- 검증: SN 전체 타입검사 exit0, 숫자/소수/삭제 및 거부 문자열 Node 검증 통과, git diff --check 통과. 실브라우저 입력 검증은 미수행.
|
||||
- 수정 소스: `frontend/apps/sn/src/features/exmn/ui/exmn-business-register-popup-page.tsx`. API/백엔드 코드·저장 계약 변경 없음. 기존 GIS 작업은 변경하지 않았다.
|
||||
- 롤백: 해당 소스의 이번 필수 표시/입력 제한만 복원한다.
|
||||
|
||||
|
||||
## 2026-10-19 맨홀 조사보고서 GIS 번호 연결 (maintenance)
|
||||
|
||||
- 목적: 별도 맨홀 식별체계 확정 전 맨홀 PDF의 `맨홀번호`에 조사시설 GIS 번호(테스트 188001)를 넣고 지도에서 해당 보고서를 열람한다. 지도 도형은 기존 상류맨홀 매칭을 유지한다.
|
||||
- 근거: 요구사항정의서 `3. (기능)요구사항정의 및 추적표` SFR-010-006/007, 화면설계서 실제 42쪽의 식별기준 미확정 메모 및 43쪽 `SN_MN040101` 조사결과 등록. 이번 사용자 지시로 임시 GIS 번호 연결 기준을 확정했다.
|
||||
- BE: `ExmnManholeReportService.java` 신규, `ExmnPipePdfValidator.java` 표제별 불변 판독기, `ExmnBusinessController.java`의 `GET /api/v1/exmnBusinesses/{exmnBizId}/manholeReports/{pipeNumber}` 및 `/availability`, `ExmnFacilityRepository.java`의 조사유형별 첨부 존재 여부 분기.
|
||||
- 맨홀 첨부 `mnhlExmnAtchFileId`와 활성 MNHL의 `gisManagementNo`만 사용한다. 선택 번호가 없거나 활성 시설이 중복되면 임의 보고서를 반환하지 않는다. 매 요청 현재 PDF를 판독하므로 이전 관로 쪽 캐시를 사용하지 않는다. DB 스키마 및 업무 데이터 변경 없음.
|
||||
- FE: `exmn-business-api.ts`, `exmn-survey-result-section.tsx`, `exmn-pipe-report-popup-content.tsx`, `exmn-result-register-popup-page.tsx`. MNHL에서도 보고서 버튼을 표시하고 jobType에 따라 API·제목·번호 안내를 선택한다. PPL 기본 호출은 유지한다.
|
||||
- 업로드 검토의 PDF 내부 번호 대조는 이번 범위에 추가하지 않았다. 번호 입력 기준과 열람 시 대조한다는 안내를 결과등록 화면에 표시한다.
|
||||
- 산출물: 작업루트 `output/pdf/맨홀_현황조사_보고서_188001.pdf`. 사용자 원본 1쪽의 맨홀번호만 188001로 변경했으며 보고서번호·노선명 등 예시값과 사진은 원본을 유지했다. 실제 납품 조사자료가 아닌 기능 테스트용이다.
|
||||
- 검증: BE compileJava --offline 성공, SN 전체 typecheck 성공, 양 저장소 diff --check 성공. 임시 JUnit 5건 성공(실제 PDF 번호/쪽 추출, PPL 표제 분리, 다중/비연속 번호 거부·연속 쪽, MNHL 첨부 선택/DB 캐시 미사용/미첨부, 없는 번호/중복 시설). PDF 재열람·텍스트 및 렌더링 육안 검증 완료.
|
||||
- 미검증: 로컬 3002/8883 실행 포트가 없으므로 실제 서버 업로드·저장·지도 선택·브라우저 팝업은 수행하지 않았다. 188001 MNHL 조사시설 및 상류맨홀 GIS 도형의 실제 존재를 확인한 것으로 간주하지 않는다.
|
||||
- 수동 절차: 변경 BE/FE 실행 → 188001을 가진 MNHL 조사자료의 사업에서 결과등록 → CCTV 조사결과(맨홀)에 테스트 PDF 등록·저장 → 맨홀조사 레이어의 해당 상류맨홀 선택 → 조사보고서 보기 → 제목 맨홀 조사보고서/GIS 번호188001/1쪽 확인. 관로 보고서와 미첨부·없는 번호도 회귀 확인한다.
|
||||
- 롤백: 위 소스의 이번 변경과 신규 ExmnManholeReportService를 함께 복원한다. DB 롤백은 없다. 실제 첨부 등록을 수행한 경우에는 별도로 이전 첨부를 복원한다.
|
||||
- 남은 리스크: 번호는 확정 맨홀번호가 아닌 조사시설 GIS 번호의 임시 계약이며, 스캔 PDF는 판독 불가하다. 맨홀 PDF는 availability/열람 때 각각 판독하므로 대형 파일 성능은 후속 검증 대상이다. 테스트 소스·원시 결과·렌더링 임시 이미지는 요약 후 정리하고 최종 PDF는 보존한다.
|
||||
|
||||
|
||||
## 2026-10-19 후속: 기존 사업 맨홀 PDF 단독 교체
|
||||
- 원인: 보고서 열람을 추가했지만 결과등록 화면은 모든 검토에 Excel을 요구하고 저장에 Excel·PPL 검토 성공을 요구했다.
|
||||
- 변경: 맨홀 PDF 하나만 선택하면 기존 활성 MNHL 조사시설의 GIS 번호로 PDF 번호를 대조한다. 기존 조사자료 없음·불일치·중복·잘못된 PDF는 차단한다. 선택 PDF의 일부 시설 포함은 허용한다.
|
||||
- 저장 직전 다시 검토한 뒤 선택한 MNHL 첨부만 기존 attachments API로 연결한다. Excel imports/commit과 양식 생성 확인은 호출하지 않아 기존 시설·집계·관로첨부를 유지한다. Excel을 선택한 신규/전체 결과 저장 흐름은 유지한다.
|
||||
- 수정: BE ExmnBusinessController(선택 mnhlFile 입력 및 Excel 없는 MNHL 검토 분기), ExmnManholeReportService(validateReplacement), FE exmn-result-register-popup-page(검토·저장 조건과 검토안내).
|
||||
- 검증: BE compileJava, SN typecheck, 임시 JUnit 4건(기존번호 정상·무쓰기, 기존결과 없음, 번호 불일치/중복, 누락/손상 PDF) 통과. 원본 요구사항·지도 기준은 앞선 절과 동일하다. DB 스키마 변경 없음.
|
||||
- 롤백: 이번 단독 교체 분기만 복원한다. 앞선 맨홀 보고서 열람 구현은 유지할 수 있다.
|
||||
|
||||
- 실제 브라우저 확인: 기존 테스트 사업 `6fe818cb-0a7a-4379-969c-150150155f91`에서 Excel/PPL 미선택·188001 맨홀 PDF만 선택 → 검토 완료 → 저장 → 부모 사업목록 성공 안내 확인. 등록한 맨홀 PDF를 보고서 팝업에서 GIS 번호188001/1쪽으로 실제 표시했다. 지도 클릭 경로 자체는 이번 후속에서 재실행하지 않았다.
|
||||
- 검토 중 기존8883 서버의 닫힌 Spring 컨텍스트로 일반 API도500 발생. 사용자 명시 승인 후 동일 실행인수·local 프로필·포트8883·context /sewerage-service로 재시작하여 정상화했다. 교체 서버 PID24204는 사용자가 이어서 테스트하도록 유지한다. 종료명령: Stop-Process -Id 24204. 실행중 필요한 classpath 사본과 stdout/stderr는 작업루트 .codex-tmp/manhole-backend-classpath.jar 및 manhole-backend.out.log/err.log에 유지한다(테스트용 임시 서버가 아닌 승인된 사용자 서버 교체).
|
||||
- 부모 성공문구도 첨부 교체에 맞게 `조사결과 저장을 완료했습니다.`로 보정했다(exmn-registration-page.tsx). 실제 첨부는 변경했으며 기존 시설·집계는 Excel commit을 호출하지 않아 유지한다. 되돌릴 경우 이전 맨홀 첨부를 재등록한다.
|
||||
|
||||
|
||||
## 2026-10-19 최종 정정: 실제 GIS 맨홀번호와 선택 사업 기준
|
||||
- 사용자 확정: PDF 맨홀번호는 조사자료 관로번호가 아닌 실제 GIS 맨홀번호이다. 앞선 gisManagementNo 기준 설명·구현은 이 절로 대체한다.
|
||||
- 원인: 지도보기 진입은 테스트 사업이었지만 전체 사업 레이어의 겹친 시설이 선택됐다. 실제 화면은 오류 확인 테스트_수정/조사관로188003/시설관리번호188001이었다. 사용자 선택 실수가 아닌 지도 범위와 번호 계약 불일치이다.
|
||||
- FE use-exmn-result-map.ts: 조사관리에서 사업·처리분구를 지정해 진입하면 해당 범위만 표출·선택한다. 일반 지도 진입은 기존 전체 범위를 유지한다. 기존 2026-10-01 전체표출 정책의 조사관리 진입 부분을 이 결정으로 대체한다.
|
||||
- FE exmn-survey-result-section.tsx: MNHL 보고서 키는 fclt_mng_no/fcltMngNo, PPL은 기존 gisManagementNo. 조사 결과 표에 GIS 번호를 명시한다. 결과등록 안내도 실제 GIS 맨홀번호로 정정했다.
|
||||
- BE ExmnManholeReportService: 기존 ExmnMapLayerService의 동일 지역·상류맨홀 매칭 결과 fclt_mng_no 집합으로 업로드 검토·열람 대상을 확인한다. 조사 관로번호를 맨홀번호로 대체하지 않는다. 같은 실제 맨홀에 여러 조사관로가 연결되면 번호 집합으로 처리한다. 스키마·조사시설·원천 GIS 변경 없음.
|
||||
- 검증: 실제 GIS188001/조사관로188003 분리, PDF 검토·열람 성공, 조사관로 번호 직접 요청 거부 및 GIS 미연결 거부를 묶은 JUnit1건 통과. BE 컴파일·FE 타입검사·diff --check 통과. 임시 테스트 소스와 결과 정리 완료.
|
||||
- 실브라우저: 테스트 사업→초이처리분구→지도3개 표시→실제188001 클릭→사업명 테스트/GIS 맨홀번호188001 확인→조사보고서 보기→1쪽 PDF와188001 표시 성공. 사용자도 최종 정상동작 확인했다.
|
||||
- 실행 서버: 기존 재시작 승인 범위에서 코드 반영 후8883 PID27788로 유지한다(이전PID24204 종료). classpath/실행로그는 기존 .codex-tmp/manhole-backend-* 경로 유지. 종료명령 Stop-Process -Id 27788.
|
||||
- 롤백: 위 FE3개 소스와 ExmnManholeReportService의 이번 변경을 함께 복원한다. DB 롤백 없음. 잔여 리스크는 GIS 미연결 자료 열람 불가 및 대형 사업의 지도 매칭·PDF 판독 비용이며, 임의 위치/다른 사업 fallback을 하지 않는다.
|
||||
|
||||
@@ -1004,3 +1004,44 @@
|
||||
- 검증: SN 전체 타입검사 exit0, 숫자/소수/삭제 및 거부 문자열 Node 검증 통과, git diff --check 통과. 실브라우저 입력 검증은 미수행.
|
||||
- 수정 소스: `frontend/apps/sn/src/features/exmn/ui/exmn-business-register-popup-page.tsx`. API/백엔드 코드·저장 계약 변경 없음. 기존 GIS 작업은 변경하지 않았다.
|
||||
- 롤백: 해당 소스의 이번 필수 표시/입력 제한만 복원한다.
|
||||
|
||||
|
||||
## 2026-10-19 맨홀 조사보고서 GIS 번호 연결 (maintenance)
|
||||
|
||||
- 목적: 별도 맨홀 식별체계 확정 전 맨홀 PDF의 `맨홀번호`에 조사시설 GIS 번호(테스트 188001)를 넣고 지도에서 해당 보고서를 열람한다. 지도 도형은 기존 상류맨홀 매칭을 유지한다.
|
||||
- 근거: 요구사항정의서 `3. (기능)요구사항정의 및 추적표` SFR-010-006/007, 화면설계서 실제 42쪽의 식별기준 미확정 메모 및 43쪽 `SN_MN040101` 조사결과 등록. 이번 사용자 지시로 임시 GIS 번호 연결 기준을 확정했다.
|
||||
- BE: `ExmnManholeReportService.java` 신규, `ExmnPipePdfValidator.java` 표제별 불변 판독기, `ExmnBusinessController.java`의 `GET /api/v1/exmnBusinesses/{exmnBizId}/manholeReports/{pipeNumber}` 및 `/availability`, `ExmnFacilityRepository.java`의 조사유형별 첨부 존재 여부 분기.
|
||||
- 맨홀 첨부 `mnhlExmnAtchFileId`와 활성 MNHL의 `gisManagementNo`만 사용한다. 선택 번호가 없거나 활성 시설이 중복되면 임의 보고서를 반환하지 않는다. 매 요청 현재 PDF를 판독하므로 이전 관로 쪽 캐시를 사용하지 않는다. DB 스키마 및 업무 데이터 변경 없음.
|
||||
- FE: `exmn-business-api.ts`, `exmn-survey-result-section.tsx`, `exmn-pipe-report-popup-content.tsx`, `exmn-result-register-popup-page.tsx`. MNHL에서도 보고서 버튼을 표시하고 jobType에 따라 API·제목·번호 안내를 선택한다. PPL 기본 호출은 유지한다.
|
||||
- 업로드 검토의 PDF 내부 번호 대조는 이번 범위에 추가하지 않았다. 번호 입력 기준과 열람 시 대조한다는 안내를 결과등록 화면에 표시한다.
|
||||
- 산출물: 작업루트 `output/pdf/맨홀_현황조사_보고서_188001.pdf`. 사용자 원본 1쪽의 맨홀번호만 188001로 변경했으며 보고서번호·노선명 등 예시값과 사진은 원본을 유지했다. 실제 납품 조사자료가 아닌 기능 테스트용이다.
|
||||
- 검증: BE compileJava --offline 성공, SN 전체 typecheck 성공, 양 저장소 diff --check 성공. 임시 JUnit 5건 성공(실제 PDF 번호/쪽 추출, PPL 표제 분리, 다중/비연속 번호 거부·연속 쪽, MNHL 첨부 선택/DB 캐시 미사용/미첨부, 없는 번호/중복 시설). PDF 재열람·텍스트 및 렌더링 육안 검증 완료.
|
||||
- 미검증: 로컬 3002/8883 실행 포트가 없으므로 실제 서버 업로드·저장·지도 선택·브라우저 팝업은 수행하지 않았다. 188001 MNHL 조사시설 및 상류맨홀 GIS 도형의 실제 존재를 확인한 것으로 간주하지 않는다.
|
||||
- 수동 절차: 변경 BE/FE 실행 → 188001을 가진 MNHL 조사자료의 사업에서 결과등록 → CCTV 조사결과(맨홀)에 테스트 PDF 등록·저장 → 맨홀조사 레이어의 해당 상류맨홀 선택 → 조사보고서 보기 → 제목 맨홀 조사보고서/GIS 번호188001/1쪽 확인. 관로 보고서와 미첨부·없는 번호도 회귀 확인한다.
|
||||
- 롤백: 위 소스의 이번 변경과 신규 ExmnManholeReportService를 함께 복원한다. DB 롤백은 없다. 실제 첨부 등록을 수행한 경우에는 별도로 이전 첨부를 복원한다.
|
||||
- 남은 리스크: 번호는 확정 맨홀번호가 아닌 조사시설 GIS 번호의 임시 계약이며, 스캔 PDF는 판독 불가하다. 맨홀 PDF는 availability/열람 때 각각 판독하므로 대형 파일 성능은 후속 검증 대상이다. 테스트 소스·원시 결과·렌더링 임시 이미지는 요약 후 정리하고 최종 PDF는 보존한다.
|
||||
|
||||
|
||||
## 2026-10-19 후속: 기존 사업 맨홀 PDF 단독 교체
|
||||
- 원인: 보고서 열람을 추가했지만 결과등록 화면은 모든 검토에 Excel을 요구하고 저장에 Excel·PPL 검토 성공을 요구했다.
|
||||
- 변경: 맨홀 PDF 하나만 선택하면 기존 활성 MNHL 조사시설의 GIS 번호로 PDF 번호를 대조한다. 기존 조사자료 없음·불일치·중복·잘못된 PDF는 차단한다. 선택 PDF의 일부 시설 포함은 허용한다.
|
||||
- 저장 직전 다시 검토한 뒤 선택한 MNHL 첨부만 기존 attachments API로 연결한다. Excel imports/commit과 양식 생성 확인은 호출하지 않아 기존 시설·집계·관로첨부를 유지한다. Excel을 선택한 신규/전체 결과 저장 흐름은 유지한다.
|
||||
- 수정: BE ExmnBusinessController(선택 mnhlFile 입력 및 Excel 없는 MNHL 검토 분기), ExmnManholeReportService(validateReplacement), FE exmn-result-register-popup-page(검토·저장 조건과 검토안내).
|
||||
- 검증: BE compileJava, SN typecheck, 임시 JUnit 4건(기존번호 정상·무쓰기, 기존결과 없음, 번호 불일치/중복, 누락/손상 PDF) 통과. 원본 요구사항·지도 기준은 앞선 절과 동일하다. DB 스키마 변경 없음.
|
||||
- 롤백: 이번 단독 교체 분기만 복원한다. 앞선 맨홀 보고서 열람 구현은 유지할 수 있다.
|
||||
|
||||
- 실제 브라우저 확인: 기존 테스트 사업 `6fe818cb-0a7a-4379-969c-150150155f91`에서 Excel/PPL 미선택·188001 맨홀 PDF만 선택 → 검토 완료 → 저장 → 부모 사업목록 성공 안내 확인. 등록한 맨홀 PDF를 보고서 팝업에서 GIS 번호188001/1쪽으로 실제 표시했다. 지도 클릭 경로 자체는 이번 후속에서 재실행하지 않았다.
|
||||
- 검토 중 기존8883 서버의 닫힌 Spring 컨텍스트로 일반 API도500 발생. 사용자 명시 승인 후 동일 실행인수·local 프로필·포트8883·context /sewerage-service로 재시작하여 정상화했다. 교체 서버 PID24204는 사용자가 이어서 테스트하도록 유지한다. 종료명령: Stop-Process -Id 24204. 실행중 필요한 classpath 사본과 stdout/stderr는 작업루트 .codex-tmp/manhole-backend-classpath.jar 및 manhole-backend.out.log/err.log에 유지한다(테스트용 임시 서버가 아닌 승인된 사용자 서버 교체).
|
||||
- 부모 성공문구도 첨부 교체에 맞게 `조사결과 저장을 완료했습니다.`로 보정했다(exmn-registration-page.tsx). 실제 첨부는 변경했으며 기존 시설·집계는 Excel commit을 호출하지 않아 유지한다. 되돌릴 경우 이전 맨홀 첨부를 재등록한다.
|
||||
|
||||
|
||||
## 2026-10-19 최종 정정: 실제 GIS 맨홀번호와 선택 사업 기준
|
||||
- 사용자 확정: PDF 맨홀번호는 조사자료 관로번호가 아닌 실제 GIS 맨홀번호이다. 앞선 gisManagementNo 기준 설명·구현은 이 절로 대체한다.
|
||||
- 원인: 지도보기 진입은 테스트 사업이었지만 전체 사업 레이어의 겹친 시설이 선택됐다. 실제 화면은 오류 확인 테스트_수정/조사관로188003/시설관리번호188001이었다. 사용자 선택 실수가 아닌 지도 범위와 번호 계약 불일치이다.
|
||||
- FE use-exmn-result-map.ts: 조사관리에서 사업·처리분구를 지정해 진입하면 해당 범위만 표출·선택한다. 일반 지도 진입은 기존 전체 범위를 유지한다. 기존 2026-10-01 전체표출 정책의 조사관리 진입 부분을 이 결정으로 대체한다.
|
||||
- FE exmn-survey-result-section.tsx: MNHL 보고서 키는 fclt_mng_no/fcltMngNo, PPL은 기존 gisManagementNo. 조사 결과 표에 GIS 번호를 명시한다. 결과등록 안내도 실제 GIS 맨홀번호로 정정했다.
|
||||
- BE ExmnManholeReportService: 기존 ExmnMapLayerService의 동일 지역·상류맨홀 매칭 결과 fclt_mng_no 집합으로 업로드 검토·열람 대상을 확인한다. 조사 관로번호를 맨홀번호로 대체하지 않는다. 같은 실제 맨홀에 여러 조사관로가 연결되면 번호 집합으로 처리한다. 스키마·조사시설·원천 GIS 변경 없음.
|
||||
- 검증: 실제 GIS188001/조사관로188003 분리, PDF 검토·열람 성공, 조사관로 번호 직접 요청 거부 및 GIS 미연결 거부를 묶은 JUnit1건 통과. BE 컴파일·FE 타입검사·diff --check 통과. 임시 테스트 소스와 결과 정리 완료.
|
||||
- 실브라우저: 테스트 사업→초이처리분구→지도3개 표시→실제188001 클릭→사업명 테스트/GIS 맨홀번호188001 확인→조사보고서 보기→1쪽 PDF와188001 표시 성공. 사용자도 최종 정상동작 확인했다.
|
||||
- 실행 서버: 기존 재시작 승인 범위에서 코드 반영 후8883 PID27788로 유지한다(이전PID24204 종료). classpath/실행로그는 기존 .codex-tmp/manhole-backend-* 경로 유지. 종료명령 Stop-Process -Id 27788.
|
||||
- 롤백: 위 FE3개 소스와 ExmnManholeReportService의 이번 변경을 함께 복원한다. DB 롤백 없음. 잔여 리스크는 GIS 미연결 자료 열람 불가 및 대형 사업의 지도 매칭·PDF 판독 비용이며, 임의 위치/다른 사업 fallback을 하지 않는다.
|
||||
|
||||
@@ -341,9 +341,10 @@ export const downloadExmnBusinessReport = async (
|
||||
export const downloadExmnPipeReport = async (
|
||||
exmnBizId: string,
|
||||
pipeNumber: string,
|
||||
jobType: "PPL" | "MNHL" = "PPL",
|
||||
): Promise<Blob> =>
|
||||
getBlobData(
|
||||
`${EXMN_BUSINESS_API_PATH}/${encodeURIComponent(exmnBizId)}/pipeReports/${encodeURIComponent(pipeNumber)}`,
|
||||
`${EXMN_BUSINESS_API_PATH}/${encodeURIComponent(exmnBizId)}/${jobType === "MNHL" ? "manholeReports" : "pipeReports"}/${encodeURIComponent(pipeNumber)}`,
|
||||
);
|
||||
|
||||
/** 사업 파일별 첨부서비스 키 쌍을 조사사업에 연결한다. */
|
||||
@@ -351,9 +352,10 @@ export const downloadExmnPipeReport = async (
|
||||
export const getExmnPipeReportAvailability = async (
|
||||
exmnBizId: string,
|
||||
pipeNumber: string,
|
||||
jobType: "PPL" | "MNHL" = "PPL",
|
||||
): Promise<ExmnPipeReportAvailability> =>
|
||||
getData(
|
||||
`${EXMN_BUSINESS_API_PATH}/${encodeURIComponent(exmnBizId)}/pipeReports/${encodeURIComponent(pipeNumber)}/availability`,
|
||||
`${EXMN_BUSINESS_API_PATH}/${encodeURIComponent(exmnBizId)}/${jobType === "MNHL" ? "manholeReports" : "pipeReports"}/${encodeURIComponent(pipeNumber)}/availability`,
|
||||
) as Promise<ExmnPipeReportAvailability>;
|
||||
|
||||
export const updateExmnAttachments = async (
|
||||
|
||||
@@ -385,7 +385,7 @@ export function ExmnRegistrationPage() {
|
||||
if (refreshed)
|
||||
setNotice({
|
||||
type: "success",
|
||||
text: "조사결과 최종 저장과 PPL/MNHL 집계를 완료했습니다.",
|
||||
text: "조사결과 저장을 완료했습니다.",
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ const VALIDATION_CHECK_GUIDES: Partial<
|
||||
},
|
||||
MNHL_EXMN_PDF: {
|
||||
checkedItems: ["PDF 파일 형식", "조사결과 Excel 구조 및 저장 가능 여부"],
|
||||
pendingNote: "PDF 내부 맨홀번호 대조는 검토 기준 협의 후 적용 예정입니다.",
|
||||
pendingNote: "맨홀보고서의 맨홀번호에는 실제 GIS 맨홀번호를 입력해주세요. 보고서 열람 시 번호를 대조하며, 업로드 검토에는 PDF 내부 번호 대조가 포함되지 않습니다.",
|
||||
},
|
||||
};
|
||||
|
||||
@@ -179,6 +179,9 @@ export function ExmnResultRegisterPopupPage({
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [notice, setNotice] = useState<Notice>(null);
|
||||
|
||||
/** 맨홀 PDF 하나만 선택한 경우 기존 조사자료의 첨부 교체로 처리한다. */
|
||||
const isManholeOnly = Boolean(files.MNHL_EXMN_PDF) && Object.keys(files).length === 1;
|
||||
|
||||
/** popup layout 상위 html/body에서 생기는 문서 스크롤바를 팝업이 열린 동안 잠근다. */
|
||||
useEffect(() => {
|
||||
const previousHtmlOverflow = document.documentElement.style.overflow;
|
||||
@@ -310,7 +313,9 @@ export function ExmnResultRegisterPopupPage({
|
||||
const fileMap = Object.fromEntries(
|
||||
Object.entries(files).map(([type, selected]) => [type, selected?.file]),
|
||||
) as Partial<Record<ExmnFileType, File>>;
|
||||
const validationMessage = validateExmnFiles(fileMap);
|
||||
const validationMessage = isManholeOnly
|
||||
? validateExmnFile("MNHL_EXMN_PDF", files.MNHL_EXMN_PDF!.file)
|
||||
: validateExmnFiles(fileMap);
|
||||
if (validationMessage) {
|
||||
setFileValidationStatuses((current) => ({
|
||||
...current,
|
||||
@@ -373,22 +378,22 @@ export function ExmnResultRegisterPopupPage({
|
||||
/** 정상 검토된 조사결과 Excel을 저장하고 부모 화면에 완료 메시지를 보낸 뒤 팝업을 닫는다. */
|
||||
const handleCommit = async () => {
|
||||
const excelValidation = validationResults.EXMN_EXCEL;
|
||||
if (
|
||||
!excelValidation?.valid ||
|
||||
fileValidationStatuses.EXMN_EXCEL !== "success" ||
|
||||
fileValidationStatuses.PPL_EXMN_PDF !== "success"
|
||||
)
|
||||
return;
|
||||
if (!canCommit) return;
|
||||
setIsLoading(true);
|
||||
setNotice(null);
|
||||
try {
|
||||
if (!(await ensureTemplateReady())) return;
|
||||
if (!isManholeOnly && !(await ensureTemplateReady())) return;
|
||||
// 로딩 화면이 저장 확인창을 가리지 않도록 사전 확인과 업로드 상태를 나눈다.
|
||||
setIsLoading(false);
|
||||
if (!(await confirm("조사결과를 저장하시겠습니까?"))) return;
|
||||
setIsLoading(true);
|
||||
if (isManholeOnly) {
|
||||
// 검토 이후 기존 조사자료가 변경됐을 수 있어 첨부 업로드 직전에 다시 대조한다.
|
||||
const result = await validateExmnImport(exmnBizId, buildImportFormData(files, null, "MNHL_EXMN_PDF"));
|
||||
if (!result.valid) throw new Error(result.errors.map((item) => item.message).join("\n"));
|
||||
}
|
||||
await uploadAndLinkAttachments();
|
||||
await commitExmnImport(
|
||||
if (!isManholeOnly) await commitExmnImport(
|
||||
exmnBizId,
|
||||
buildImportFormData(files, excelValidation),
|
||||
);
|
||||
@@ -418,6 +423,11 @@ export function ExmnResultRegisterPopupPage({
|
||||
(fileType) => fileValidationStatuses[fileType],
|
||||
);
|
||||
const excelValidation = validationResults.EXMN_EXCEL;
|
||||
/** 단독 첨부 교체와 신규 Excel 결과 저장의 필수 검토 조건을 분리한다. */
|
||||
const canCommit = isManholeOnly
|
||||
? fileValidationStatuses.MNHL_EXMN_PDF === "success" && Boolean(validationResults.MNHL_EXMN_PDF?.valid)
|
||||
: Boolean(excelValidation?.valid) && fileValidationStatuses.EXMN_EXCEL === "success"
|
||||
&& fileValidationStatuses.PPL_EXMN_PDF === "success";
|
||||
|
||||
return (
|
||||
<StandardPopupLayout
|
||||
@@ -429,10 +439,7 @@ export function ExmnResultRegisterPopupPage({
|
||||
type="button"
|
||||
color="primary"
|
||||
disabled={
|
||||
isLoading ||
|
||||
!excelValidation?.valid ||
|
||||
fileValidationStatuses.EXMN_EXCEL !== "success" ||
|
||||
fileValidationStatuses.PPL_EXMN_PDF !== "success"
|
||||
isLoading || !canCommit
|
||||
}
|
||||
onClick={() => void handleCommit()}
|
||||
>
|
||||
@@ -614,7 +621,9 @@ export function ExmnResultRegisterPopupPage({
|
||||
const status = fileValidationStatuses[fileType]!;
|
||||
const result = validationResults[fileType];
|
||||
const messages = fileValidationMessages[fileType] ?? [];
|
||||
const guide = VALIDATION_CHECK_GUIDES[fileType];
|
||||
const guide = fileType === "MNHL_EXMN_PDF" && isManholeOnly
|
||||
? { checkedItems: ["PDF 맨홀번호 판독", "기존 조사자료에 연결된 실제 GIS 맨홀번호와 대조"], pendingNote: "저장 시 기존 조사자료는 유지하고 맨홀 보고서만 교체합니다." }
|
||||
: VALIDATION_CHECK_GUIDES[fileType];
|
||||
const countText =
|
||||
fileType === "EXMN_EXCEL"
|
||||
? `관로 ${result?.summary.pplCount ?? 0}건 · 맨홀 ${result?.summary.mnhlCount ?? 0}건`
|
||||
|
||||
@@ -52,21 +52,22 @@ export default function ExmnSurveyResultSection({
|
||||
const alert = useAlertStore((state) => state.setMessage);
|
||||
const exmnBizId = readFeatureProperty(featureData, ["exmnBizId"]);
|
||||
const jobType = readFeatureProperty(featureData, ["jobType"]);
|
||||
const pipeNumber = readFeatureProperty(featureData, [
|
||||
"gisManagementNo",
|
||||
"fclt_mng_no",
|
||||
"fcltMngNo",
|
||||
]);
|
||||
// 맨홀은 조사 관로번호가 아니라 지도 원천의 실제 시설관리번호로 보고서를 조회한다.
|
||||
const pipeNumber = readFeatureProperty(featureData, jobType === "MNHL"
|
||||
? ["fclt_mng_no", "fcltMngNo"]
|
||||
: ["gisManagementNo", "fclt_mng_no", "fcltMngNo"]);
|
||||
const reportAvailable = readBooleanFeatureProperty(featureData, [
|
||||
"reportAvailable",
|
||||
]);
|
||||
/** 지도는 상류맨홀 위치를 유지하고 맨홀 보고서는 실제 GIS 맨홀번호로 연결한다. */
|
||||
const reportLabel = jobType === "MNHL" ? "맨홀" : "관로";
|
||||
const canOpenPipeReport =
|
||||
jobType === "PPL" && Boolean(exmnBizId && pipeNumber);
|
||||
(jobType === "PPL" || jobType === "MNHL") && Boolean(exmnBizId && pipeNumber);
|
||||
|
||||
const openPipeReport = async () => {
|
||||
if (!canOpenPipeReport) return;
|
||||
if (!reportAvailable) {
|
||||
alert("등록된 관로 조사보고서가 없습니다.");
|
||||
alert(`등록된 ${reportLabel} 조사보고서가 없습니다.`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -74,11 +75,12 @@ export default function ExmnSurveyResultSection({
|
||||
const availability = await getExmnPipeReportAvailability(
|
||||
exmnBizId,
|
||||
pipeNumber,
|
||||
jobType === "MNHL" ? "MNHL" : "PPL",
|
||||
);
|
||||
if (!availability.available) {
|
||||
alert(
|
||||
availability.message?.trim() ||
|
||||
`선택한 관로번호의 조사보고서가 등록된 PDF에 없습니다: ${pipeNumber}`,
|
||||
`선택한 GIS 번호의 조사보고서가 등록된 PDF에 없습니다: ${pipeNumber}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -86,6 +88,7 @@ export default function ExmnSurveyResultSection({
|
||||
const reportWindow = openWindowPopup("exmnPipeReport", {
|
||||
exmnBizId,
|
||||
pipeNumber,
|
||||
jobType,
|
||||
reportNo: readFeatureProperty(featureData, ["reportNo"]),
|
||||
});
|
||||
if (!reportWindow) {
|
||||
@@ -97,7 +100,7 @@ export default function ExmnSurveyResultSection({
|
||||
alert(
|
||||
error instanceof Error && error.message
|
||||
? error.message
|
||||
: "관로 조사보고서 열람 가능 여부를 확인하지 못했습니다.",
|
||||
: `${reportLabel} 조사보고서 열람 가능 여부를 확인하지 못했습니다.`,
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -107,6 +110,7 @@ export default function ExmnSurveyResultSection({
|
||||
["사업차수", readFeatureProperty(featureData, ["bizCycl"])],
|
||||
["처리분구", readFeatureProperty(featureData, ["trtdstNm"])],
|
||||
["조사유형", jobType === "MNHL" ? "맨홀조사" : "관로조사"],
|
||||
[jobType === "MNHL" ? "GIS 맨홀번호" : "GIS 관로번호", pipeNumber],
|
||||
["보고서번호", readFeatureProperty(featureData, ["reportNo"])],
|
||||
["구조적결함 등급", readFeatureProperty(featureData, ["structuralGrade"])],
|
||||
["운영적결함 등급", readFeatureProperty(featureData, ["operationalGrade"])],
|
||||
@@ -116,7 +120,7 @@ export default function ExmnSurveyResultSection({
|
||||
<section className="border-b border-border bg-background">
|
||||
<div className="card-header flex items-center justify-between">
|
||||
<h3 className="mx-3 text-2xl font-medium text-label">조사 결과</h3>
|
||||
{jobType === "PPL" && (
|
||||
{(jobType === "PPL" || jobType === "MNHL") && (
|
||||
<Button
|
||||
onClick={openPipeReport}
|
||||
disabled={!canOpenPipeReport}
|
||||
|
||||
@@ -14,7 +14,7 @@ const getParam = (value: string | string[] | undefined) =>
|
||||
/** 공통 Blob API 오류 문자열에서 백엔드의 사용자 안내 메시지만 추출한다. */
|
||||
const getReportErrorMessage = (error: unknown) => {
|
||||
if (!(error instanceof Error)) {
|
||||
return "관로 조사보고서를 불러오지 못했습니다.";
|
||||
return "조사보고서를 불러오지 못했습니다.";
|
||||
}
|
||||
|
||||
const backendMessage = error.message.match(
|
||||
@@ -35,6 +35,9 @@ export default function ExmnPipeReportPopupContent({
|
||||
}: WindowPopupContentProps) {
|
||||
const exmnBizId = getParam(searchParams.exmnBizId);
|
||||
const pipeNumber = getParam(searchParams.pipeNumber);
|
||||
/** 조사유형별 첨부 API와 표시 제목을 선택한다. */
|
||||
const jobType = getParam(searchParams.jobType) === "MNHL" ? "MNHL" : "PPL";
|
||||
const reportLabel = jobType === "MNHL" ? "맨홀" : "관로";
|
||||
const reportNo = getParam(searchParams.reportNo);
|
||||
const [reportUrl, setReportUrl] = useState("");
|
||||
const [errorMessage, setErrorMessage] = useState("");
|
||||
@@ -46,7 +49,7 @@ export default function ExmnPipeReportPopupContent({
|
||||
setReportUrl("");
|
||||
setErrorMessage("");
|
||||
|
||||
void downloadExmnPipeReport(exmnBizId, pipeNumber)
|
||||
void downloadExmnPipeReport(exmnBizId, pipeNumber, jobType)
|
||||
.then((blob) => {
|
||||
if (!active) return;
|
||||
|
||||
@@ -59,7 +62,7 @@ export default function ExmnPipeReportPopupContent({
|
||||
})
|
||||
.catch((error) => {
|
||||
if (!active) return;
|
||||
console.warn("관로 조사보고서 조회 실패:", error);
|
||||
console.warn("조사보고서 조회 실패:", error);
|
||||
setErrorMessage(getReportErrorMessage(error));
|
||||
});
|
||||
|
||||
@@ -67,16 +70,16 @@ export default function ExmnPipeReportPopupContent({
|
||||
active = false;
|
||||
if (objectUrl) URL.revokeObjectURL(objectUrl);
|
||||
};
|
||||
}, [exmnBizId, pipeNumber]);
|
||||
}, [exmnBizId, pipeNumber, jobType]);
|
||||
|
||||
return (
|
||||
<StandardPopupLayout
|
||||
title="관로 조사보고서"
|
||||
title={`${reportLabel} 조사보고서`}
|
||||
showDefaultCancelAction={false}
|
||||
actions={
|
||||
<>
|
||||
<span className="text-[1.05rem] text-label">
|
||||
관로번호 {pipeNumber}
|
||||
{jobType === "MNHL" ? "GIS 번호" : "관로번호"} {pipeNumber}
|
||||
{reportNo ? ` · 보고서번호 ${reportNo}` : ""}
|
||||
</span>
|
||||
<Button type="button" color="white" onClick={() => window.close()}>
|
||||
@@ -93,7 +96,7 @@ export default function ExmnPipeReportPopupContent({
|
||||
</div>
|
||||
) : reportUrl ? (
|
||||
<iframe
|
||||
title={`${pipeNumber} 관로 조사보고서`}
|
||||
title={`${pipeNumber} ${reportLabel} 조사보고서`}
|
||||
src={reportUrl}
|
||||
className="h-full w-full border border-border bg-background"
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user