From b9ac4a1c183b6f65b38eabddfca9ae4326354645 Mon Sep 17 00:00:00 2001 From: bicochan Date: Mon, 7 Sep 2026 17:05:59 +0900 Subject: [PATCH] =?UTF-8?q?[as]=20feat:=20=EC=9E=AC=EC=9B=90=ED=98=91?= =?UTF-8?q?=EC=9D=98=20=EC=84=9C=EB=B9=84=EC=8A=A4(fnrsCnsltnService)=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/as/docs/pwrk-cnsltn/development-guide.md | 150 ++---------------- .../fnrs-cnsltn/api/fnrs-cnsltn-service.ts | 27 ++++ .../src/entities/fnrs-cnsltn/api/queries.ts | 41 +++++ apps/as/src/entities/fnrs-cnsltn/index.ts | 12 ++ .../model/fnrs-cnsltn-interface.ts | 30 ++++ .../model/fnrs-cnsltn-payload-schema.ts | 15 ++ .../ui/components/floating-action-buttons.tsx | 22 ++- .../ui/attachments-form-section.tsx | 24 ++- 8 files changed, 175 insertions(+), 146 deletions(-) create mode 100644 apps/as/src/entities/fnrs-cnsltn/model/fnrs-cnsltn-payload-schema.ts diff --git a/apps/as/docs/pwrk-cnsltn/development-guide.md b/apps/as/docs/pwrk-cnsltn/development-guide.md index 863304cca..04c860dd7 100644 --- a/apps/as/docs/pwrk-cnsltn/development-guide.md +++ b/apps/as/docs/pwrk-cnsltn/development-guide.md @@ -17,7 +17,7 @@ > - `as-service` — `/api/v1/fnrs-cnsltn-mng`, `/api/v1/pwrk-cnsltn-mng`, `/api/v1/pwrk-cnsltn-doc-crt-rslt`, `/api/v1/dcrag-to` > - `as-elapr-service` — `/api/v1/elapr-dmnd`, `/api/v1/elapr-prgrs-stts`, `/api/v1/elapr-apln` > -> **현재 프론트 상태**: 재원협의(`fnrs-cnsltn`)·전자결재(`elapr`)·DC RAG TO(`dcrag-to`)는 존재한다. 실무협의(`pwrk-cnsltn-*`) 엔티티·화면은 **미구현**. 버튼 매트릭스·상태코드는 **v2.1 잔존**이며 v3.0(`FNRSSTTS`)과 불일치한다. [9절](#9-현재-코드-vs-to-be-갭) 참고. +> **현재 프론트 상태**: 재원협의(`fnrs-cnsltn`)·전자결재(`elapr`)·DC RAG TO(`dcrag-to`)는 존재한다. 실무협의(`pwrk-cnsltn-`\*) 엔티티·화면은 **미구현**. 버튼 매트릭스·상태코드는 **v2.1 잔존**이며 v3.0(`FNRSSTTS`)과 불일치한다. [9절](#9-현재-코드-vs-to-be-갭) 참고. --- @@ -25,7 +25,7 @@ 재원협의 4대 주체(기초·광역·환경청·공단)의 **상태 전이·버튼·API**를 `apps/as`에 구현할 때 쓰는 프론트엔드 가이드이다. -v1.0은 공단 접수자의 **자료검증 → 초안생성 → 웹기안기**만 다뤘다. v2.0은 2026-09-03 완결 프로세스 기준으로 **신청부터 최종종결(`TA`)까지**, 실무협의·AI 3파이프라인·결재선·보완 루프를 포함한다. +v1.0은 공단 접수자의 **자료검증 → 초안생성 → 웹기안기**만 다뤘다. v2.0은 2026-09-03 완결 프로세스 기준으로 **신청부터 최종종결(**`TA`**)까지**, 실무협의·AI 3파이프라인·결재선·보완 루프를 포함한다. 상세 표·시퀀스·DTO는 본문에 넣지 않고 레퍼런스로 분리한다. 구현 중에는 본문의 규칙만 보고, 표가 필요하면 해당 파일을 연다. @@ -92,7 +92,7 @@ v1.0은 공단 접수자의 **자료검증 → 초안생성 → 웹기안기** ## 4. 상태코드 한눈에 보기 -상위코드 **`FNRSSTTS`**. v1.0의 `PWRKSTTS`(`DV`, `AR`, `TR` 등)는 **폐기**한다. +상위코드 `FNRSSTTS`. v1.0의 `PWRKSTTS`(`DV`, `AR`, `TR` 등)는 **폐기**한다. 정방향: @@ -122,7 +122,7 @@ SV → ST → LE → FV → ER → AC → TE → TP → RM → RB → RC → RA | `RK` | 조치결과서검토 | 웹기안기·금액검증 재실행·보완. 결재선 2차 | | `RR` | 조치결과서검토 회신 | 환경청 → 광역 `EP` | | `EP` | 검토결과 회신 | 광역 → 기초 `TA` | -| `TA` | 검토결과 회신(종료) | 기초 조회만. **고시(`TB`) 아님** | +| `TA` | 검토결과 회신(종료) | 기초 조회만. **고시(**`TB`**) 아님** | 코드 의미·구버전 대조·보완 루프·AI Fallback은 [ref-process-status.md](./ref-process-status.md). @@ -130,17 +130,19 @@ SV → ST → LE → FV → ER → AC → TE → TP → RM → RB → RC → RA ## 5. 프론트가 지켜야 할 핵심 규칙 -1. **상태 SSOT는 `FNRSSTTS`**. 버튼 가시성은 `(dtlInstCd, prgrsSttsComCd, atrzSeComCd)`로만 계산한다. 공단은 결재선 구분(`ATRZ01` 접수자, `ATRZ02` 검토자, `ATRZ03` 승인자, `ATRZ99` 최종승인자)을 추가로 본다. +1. **상태 SSOT는** `FNRSSTTS`. 버튼 가시성은 `(dtlInstCd, prgrsSttsComCd, atrzSeComCd)`로만 계산한다. 공단은 결재선 구분(`ATRZ01` 접수자, `ATRZ02` 검토자, `ATRZ03` 승인자, `ATRZ99` 최종승인자)을 추가로 본다. 2. **AI 콜백 API는 화면에서 호출하지 않는다.** `POST /dcrag/documents/verify-result`, `POST /dcrag/draft/complete`, `POST /dcrag/cost/verify-result`는 서버 전용이다. 3. **초안생성 1차 트리거는 검토자지정이다.** `POST /elapr-dmnd` (`ER → AC`). 예전처럼 `POST /pwrk-cnsltn-mng`로 초안을 시작하지 않는다. -4. **기술검토 의뢰는 `LE → FV` 전용 API** `POST /fnrs-cnsltn-mng/{docNo}/request-examine`. 현재 코드의 `updatePrgrsStts(ER)` 직행은 폐기. +4. **기술검토 의뢰는** `LE → FV` **전용 API** `POST /fnrs-cnsltn-mng/{docNo}/request-examine`. 현재 코드의 `updatePrgrsStts(ER)` 직행은 폐기. 5. **수동 AI 재실행은 상태를 바꾸지 않는다.** - - `ER` 파일검증 → `POST /dcrag-to/documents/transfer` - - `TE` 초안생성 → `POST /dcrag-to/documents/draft/generate` (타임아웃·실패 시에만) - - `RK` 금액검증 → `POST /dcrag-to/documents/cost/verify` -6. **진행상태만 바꾸는 버튼은 `POST /fnrs-cnsltn-mng/doc/updatePrgrsStts`를 재사용한다.** (`ST→LE`, `RM→RB`, `RC→RA`, `RR→EP`, `EP→TA`) + +- `ER` 파일검증 → `POST /dcrag-to/documents/transfer` +- `TE` 초안생성 → `POST /dcrag-to/documents/draft/generate` (타임아웃·실패 시에만) +- `RK` 금액검증 → `POST /dcrag-to/documents/cost/verify` + +6. **진행상태만 바꾸는 버튼은** `POST /fnrs-cnsltn-mng/doc/updatePrgrsStts`**를 재사용한다.** (`ST→LE`, `RM→RB`, `RC→RA`, `RR→EP`, `EP→TA`) 7. **보완요청/보완완료는 공통 API** `reqsupplement` / `submitsupplement`. 복귀 상태(`ER`/`TE`/`RK`)는 서버가 이력에서 결정한다. 프론트는 직전 상태를 추측해 보내지 않는다. -8. **결재 승인/회신은 `PUT /elapr-prgrs-stts/{id}/process` 하나**. 1차 최종승인자 → `TP`, 2차 → `RR`은 서버가 Feign으로 처리한다. +8. **결재 승인/회신은** `PUT /elapr-prgrs-stts/{id}/process` **하나**. 1차 최종승인자 → `TP`, 2차 → `RR`은 서버가 Feign으로 처리한다. 9. **2차 결재선 복사는 백엔드**. `POST /elapr-apln/copy-line`은 `AV→RK` 콜백에서 호출한다. 프론트는 `RK`에서 2차 결재선을 **조회·표시**만 한다. 10. **웹기안기는 URL을 직접 Open**. blob Object URL을 `HwpCtrl.Open`에 넘기지 않는다. `orgnlOtptDocCn`은 쓰지 않는다. @@ -209,7 +211,7 @@ END 프론트가 치는 것만. 콜백·스케줄러는 제외. | 주체 | 버튼 | From → To | Method & URI | -| --------- | -------------------------- | ----------------------------- | --------------------------------------------------------------- | +| --------- | -------------------------- | ----------------------------- | --------------------------------------------------------------- | --- | ------------------------------------------------ | | 기초 | 저장 / 신청완료 | →`SV` / `SV→ST` | `POST /fnrs-cnsltn-mng/save-apply` | | 기초 | 삭제 | `SV` | `DELETE /fnrs-cnsltn-mng/{docNo}` | | 광역 | 환경청제출 | `ST→LE` | `POST /fnrs-cnsltn-mng/doc/updatePrgrsStts` | @@ -224,7 +226,7 @@ END | 공단 검토 | 저장 | `TE`/`RK` | `POST /pwrk-cnsltn-mng/save-apply` | | 공단 | 검토완료 / 결재(승인·회신) | `TE` 유지 / `TE→TP` / `RK→RR` | `PUT /elapr-prgrs-stts/{id}/process` | | 공단 검토 | 보완요청 | `TE→SL` / `RK→SL` | `POST /fnrs-cnsltn-mng/{docNo}/reqsupplement` | -| 기초 | 파일보완완료 / 보완완료 | `SL→ER\|TE\|RK` | `POST /fnrs-cnsltn-mng/{docNo}/submitsupplement` | +| 기초 | 파일보완완료 / 보완완료 | `SL→ER | TE | RK` | `POST /fnrs-cnsltn-mng/{docNo}/submitsupplement` | | 환경청 | 재원협의 결과 회신 | `TP→RM` | `POST /fnrs-cnsltn-mng/{docNo}/tech-review` | | 광역 | 지자체회신 | `RM→RB` | `updatePrgrsStts` | | 기초 | 저장(조치) / 협의회신 | `RB` / `RB→RC` | **신규** `POST /pwrk-cnsltn-mng/{pwrkDocNo}/submit-actn-result` | @@ -239,125 +241,3 @@ END 신규 4개: `request-examine`, `submit-actn-result`, `request-actn-review`, (백엔드) `elapr-apln/copy-line`. --- - -## 8. 프론트엔드 구현 가이드 - -### 8-1. 기술 스택·원칙 - -- App Router + FSD (`app/` → `pages/` → `widgets/` → `entities/` → `shared/`) -- React Query. ad-hoc `useQuery` + service 직접 호출 금지 -- `@common/components`, `useDataTable`, `@tanstack/react-table` -- `'use client'`는 Web API(다운로드, 폴링, 웹기안기)가 있는 페이지만 -- 함수명 = Controller public 메서드명 (`delete` → `remove`) -- 타입명 = 백엔드 DTO명 -- Save/Apply Request = zod SSOT. Response는 `interface` - -참조 슬라이스: `entities/fnrs-cnsltn/`, `entities/elapr/`, `entities/dcrag-to/`, `entities/sewer-bsc-plan/` - -### 8-2. 모듈 배치 - -| 구분 | 경로 | -| ------------- | ------------------------------------------------------------------------------------------------- | -| ENDPOINT | `apps/as/src/shared/config/api.ts` | -| 재원협의 | `entities/fnrs-cnsltn/` — **확장** (`requestExamine`, `requestActnReview`, `findFileVrfcResults`) | -| 실무협의 관리 | `entities/pwrk-cnsltn-mng/` — **신규** | -| 생성결과 | `entities/pwrk-cnsltn-doc-crt-rslt/` — **신규** | -| DC RAG TO | `entities/dcrag-to/` — 구현됨 | -| 전자결재 | `entities/elapr/` — 구현됨. `copyLine`은 서버 전용 | -| 재원협의 화면 | `pages/fnrs-cnsltn/` — 버튼 매트릭스 전면 개편 | -| 실무협의 화면 | `pages/pwrk-cnsltn/` — 목록/상세 (선택, 공단 보조) | - -파일 트리·Service 시그니처·폴링 훅은 [ref-frontend-entities.md](./ref-frontend-entities.md). - -### 8-3. 버튼 매트릭스 구현 - -`pages/fnrs-cnsltn/lib/button-config.ts`를 v3.0 표로 교체한다. - -- 키: `Record>` -- 공단은 `Record>` (`ER`/`TE`/`RK`) -- AI 상태(`FV`, `AC`, `AV`)는 버튼 대신 **진행 패널** (진행률·경과시간·30분 안내) -- `SL`은 기초만 수정 버튼. 복귀 종류(파일/기술/금액)는 `sttsChgHstryList` 직전 코드로 라벨만 분기 -- `TA`는 조회 전용. **고시(`TB`) 액션 삭제** - -### 8-4. AI 3파이프라인 UX - -| 상태 | 진입 버튼 | 완료 상태 | 30분 Fallback | 수동 버튼 | -| ---- | ------------------- | --------- | ----------------------- | ----------- | -| `FV` | 기술검토 의뢰 | `ER` | `ER` + [파일검증] | 공단 접수자 | -| `AC` | 검토자지정 | `TE` | `TE` + [실무협의서생성] | 공단 검토자 | -| `AV` | 조치결과서 검토요청 | `RK` | `RK` + [금액검증] | 공단 검토자 | - -폴링: 초안은 `GET /dcrag-to/documents/draft/status/{crtDmndUuid}` (5~10초). 파일검증·금액검증은 상세 `prgrsSttsComCd` refetch로도 충분하다. `COMPLETED`/`FAILED` 또는 상태 이탈 시 중단하고 상세 invalidate. - -초안 `COMPLETED` 전에는 [실무협의서관리]·[다운로드] 비활성. Fallback으로 `TE`가 되었는데 초안이 없으면 [실무협의서생성]만 활성. - -### 8-5. 보완 팝업 3종 - -같은 `reqsupplement` / `submitsupplement`를 쓰고 팝업 UI만 나눈다. - -| 단계 | 팝업 | 요청 주체 | 복귀 | -| ---- | ------------------------- | ----------- | ---------------------- | -| `ER` | 보완 검토팝업(파일리스트) | 공단 접수자 | `SL→ER` [파일보완완료] | -| `TE` | 보완 검토팝업() | 공단 검토자 | `SL→TE` [보완완료] | -| `RK` | 보완 검토팝업(금액) | 공단 검토자 | `SL→RK` [보완완료] | - -파일 팝업 데이터: `GET /fnrs-cnsltn-mng/{docNo}/file-vrfc-results`. - ---- - -## 9. 현재 코드 vs To-Be 갭 - -`pages/fnrs-cnsltn` 기준. - -| 현재 | v3.0 | -| ------------------------------------------------------ | --------------------------------------------------------------------- | -| 기술검토 의뢰 → `updatePrgrsStts("ER")` | `request-examine` → **`FV`** | -| `ROLE_USER01` 결재 상태 `ER`, `TE`만 | `RK` 2차 결재선 추가. `ER`에 파일보완 | -| `TA` [고시] → `TB` | `TA`는 종료 조회. `TB` 없음 | -| `EP` [인가승인] → `TA` | `EP` [결과회신] → `TA` (광역) | -| `TP` 환경청 [검토결과 회신] → `EP` | `TP` → **`RM`** (1차). 최종은 `RR→EP` | -| `LE` 결과회신 → `EP` (자체종결만 맞음) | 자체종결 유지. 일반 건은 의뢰 | -| 조치결과 `RB/RC/RA/AV` 버튼 없음 | 기초 `submit-actn-result`, 광역 `RC→RA`, 환경청 `request-actn-review` | -| `SL` 수정화면 미연결 | 파일/기술/금액 3버튼 | -| 초안생성을 `pwrk-cnsltn-mng.save`로 가정 (가이드 v1.0) | **검토자지정**이 1차 트리거 | -| `pwrk-cnsltn-*` 엔티티 없음 | 신규 슬라이스 | -| `dcrag-to` 구현됨 | 수동 재실행 3종에 연결 | -| `elapr-dmnd.save` 구현됨 | `docPrgrsSttsComCd: "AC"` 로 지정 | - ---- - -## 10. 구현 순서 - -``` -Task Progress: -- [ ] 1. FNRSSTTS 상수·표시명. button-config / floating-action-buttons 를 38행 매트릭스로 교체 -- [ ] 2. fnrs-cnsltn 엔티티 확장: requestExamine, requestActnReview, findFileVrfcResults - (기존 saveApply, updatePrgrsStts, techReview, req/submit supplement 재사용) -- [ ] 3. entities/pwrk-cnsltn-mng (findPage, findById, findByUpDocNo, saveApply, submitActnResult) -- [ ] 4. entities/pwrk-cnsltn-doc-crt-rslt (download, webhwp open URL, saveMultipart) -- [ ] 5. AI 진행 패널: FV / AC / AV (draft status 폴링 + 상세 refetch, 30분 안내) -- [ ] 6. 환경청: 기술검토 의뢰(FV), 자체종결(EP), TP→RM, RA→AV, RR→EP -- [ ] 7. 공단 접수: 파일검증 결과 배지·파일보완 팝업, 검토자지정(AC) -- [ ] 8. 공단 검토 TE/RK: 웹기안기, 수동 초안/금액검증, 보완 팝업, 결재 process -- [ ] 9. 기초: SL 보완완료 3분기, RB 조치결과 submit-actn-result, TA 조회 -- [ ] 10. 광역: ST→LE, RM→RB, RC→RA, EP→TA -- [ ] 11. (선택) 실무협의 목록·상세 라우트 /pwrk-cnsltn -``` - -1~4는 엔티티·버튼 뼈대. 화면 전이는 5부터 역할 레인 단위로 닫는다. - ---- - -## 11. 공통코드 (화면 분기용) - -| 상위코드 | 필드 | 값 | 명칭 | -| ----------------------- | ---------------- | ----------------------------------- | ------------------------------ | -| `ASDOCSE` | `upDocSeComCd` | `FNRS` / `PWRK` | 재원협의 / 실무협의 | -| `FNRSSTTS` | `prgrsSttsComCd` | 18종 | [4절](#4-상태코드-한눈에-보기) | -| `AICRTSTTS` / `CRTSTTS` | `crtSttsComCd` | `R` `I` `C` `F` | 생성요청/중/완료/실패 | -| (검증) | `vrfcSttsComCd` | `PASS` / `FAIL` / `WARN` | 파일별 검증 | -| 결재선 구분 | `atrzSeComCd` | `ATRZ01` `ATRZ02` `ATRZ03` `ATRZ99` | 접수/검토/승인/최종 | - -표시명은 응답 `*Nm` / `*CdNm`. 분기는 코드값. - -초안 직후 `crtSttsComCd = R`, 폴링 `COMPLETED` 이후 `C`. 문서 상태는 `AC → TE`. diff --git a/apps/as/src/entities/fnrs-cnsltn/api/fnrs-cnsltn-service.ts b/apps/as/src/entities/fnrs-cnsltn/api/fnrs-cnsltn-service.ts index e67a9a6c7..b48e5a059 100644 --- a/apps/as/src/entities/fnrs-cnsltn/api/fnrs-cnsltn-service.ts +++ b/apps/as/src/entities/fnrs-cnsltn/api/fnrs-cnsltn-service.ts @@ -5,6 +5,7 @@ import type { PageResponse } from "@/shared/model"; import type { DocPrgrsUpdateRequestDto, FnrsCnsltnApplySaveRequestDto, + FnrsCnsltnFileVrfcRsltResponseDto, FnrsCnsltnMngDetResponseDto, FnrsCnsltnMngResponseDto, FnrsCnsltnMngSaveRequestDto, @@ -12,6 +13,10 @@ import type { FnrsCnsltnMngService, FnrsCnsltnMngUpdateRequestDto, } from "../model/fnrs-cnsltn-interface"; +import type { + EnvoActnReviewReqDto, + FnrsExamineRequestDto, +} from "../model/fnrs-cnsltn-payload-schema"; const BASE = ENDPOINT.AS_SERVICE.FNRS_CNSLTN_MNG; @@ -51,6 +56,16 @@ async function techReview(id: string, body: FnrsCnsltnApplySaveRequestDto): Prom await client.post(`${BASE}/${id}/tech-review`, body); } +async function requestExamine(docNo: string, body: FnrsExamineRequestDto): Promise { + const response = await client.post(`${BASE}/${docNo}/request-examine`, body); + return response.data; +} + +async function requestActnReview(docNo: string, body: EnvoActnReviewReqDto): Promise { + const response = await client.post(`${BASE}/${docNo}/request-actn-review`, body); + return response.data; +} + async function submitSupplement(id: string, body: FnrsCnsltnApplySaveRequestDto): Promise { const response = await client.post(`${BASE}/${id}/submitsupplement`, body); return response.data; @@ -68,6 +83,15 @@ async function remove(fnrsCnsltnDocNo: string): Promise { await client.delete(`${BASE}/${fnrsCnsltnDocNo}`); } +async function findFileVrfcResults( + fnrsCnsltnDocNo: string, +): Promise { + const response = await client.get( + `${BASE}/${fnrsCnsltnDocNo}/file-vrfc-results`, + ); + return response.data; +} + async function changePrgrsSttsComCd(body: DocPrgrsUpdateRequestDto): Promise { await client.post(`${BASE}/doc/updatePrgrsStts`, body); } @@ -79,8 +103,11 @@ export const fnrsCnsltnMngService = { saveApply, update, techReview, + requestExamine, + requestActnReview, submitSupplement, submitReqSupplement, remove, + findFileVrfcResults, changePrgrsSttsComCd, } satisfies FnrsCnsltnMngService; diff --git a/apps/as/src/entities/fnrs-cnsltn/api/queries.ts b/apps/as/src/entities/fnrs-cnsltn/api/queries.ts index 1b863a64b..357aa58c0 100644 --- a/apps/as/src/entities/fnrs-cnsltn/api/queries.ts +++ b/apps/as/src/entities/fnrs-cnsltn/api/queries.ts @@ -7,6 +7,10 @@ import type { FnrsCnsltnMngSearchDto, FnrsCnsltnMngUpdateRequestDto, } from "../model/fnrs-cnsltn-interface"; +import type { + EnvoActnReviewReqDto, + FnrsExamineRequestDto, +} from "../model/fnrs-cnsltn-payload-schema"; import { fnrsCnsltnMngService } from "./fnrs-cnsltn-service"; @@ -14,6 +18,7 @@ export const fnrsCnsltnKeys = { all: ["fnrs-cnsltn"] as const, list: () => [...fnrsCnsltnKeys.all, "list"] as const, detail: (id: string) => [...fnrsCnsltnKeys.all, "detail", id] as const, + fileVrfcResults: (id: string) => [...fnrsCnsltnKeys.all, "fileVrfcResults", id] as const, }; export function useFnrsCnsltnMngPage(params: FnrsCnsltnMngSearchDto) { @@ -31,6 +36,14 @@ export function useFnrsCnsltnMng(fnrsCnsltnDocNo: string | null | undefined) { }); } +export function useFnrsCnsltnFileVrfcResults(fnrsCnsltnDocNo: string | null | undefined) { + return useQuery({ + queryKey: fnrsCnsltnKeys.fileVrfcResults(fnrsCnsltnDocNo!), + queryFn: () => fnrsCnsltnMngService.findFileVrfcResults(fnrsCnsltnDocNo!), + enabled: Boolean(fnrsCnsltnDocNo), + }); +} + export function useSaveFnrsCnsltnMng() { const queryClient = useQueryClient(); return useMutation({ @@ -84,6 +97,34 @@ export function useTechReviewFnrsCnsltnMng() { }); } +export function useRequestExamineFnrsCnsltnMng() { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: ({ docNo, body }: { docNo: string; body: FnrsExamineRequestDto }) => + fnrsCnsltnMngService.requestExamine(docNo, body), + onSuccess: (_data, { docNo }) => { + queryClient.invalidateQueries({ queryKey: fnrsCnsltnKeys.all }); + queryClient.invalidateQueries({ + queryKey: fnrsCnsltnKeys.detail(docNo), + }); + }, + }); +} + +export function useRequestActnReviewFnrsCnsltnMng() { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: ({ docNo, body }: { docNo: string; body: EnvoActnReviewReqDto }) => + fnrsCnsltnMngService.requestActnReview(docNo, body), + onSuccess: (_data, { docNo }) => { + queryClient.invalidateQueries({ queryKey: fnrsCnsltnKeys.all }); + queryClient.invalidateQueries({ + queryKey: fnrsCnsltnKeys.detail(docNo), + }); + }, + }); +} + export function useSubmitSupplementFnrsCnsltnMng() { const queryClient = useQueryClient(); return useMutation({ diff --git a/apps/as/src/entities/fnrs-cnsltn/index.ts b/apps/as/src/entities/fnrs-cnsltn/index.ts index d7fd6cda2..31bc2f528 100644 --- a/apps/as/src/entities/fnrs-cnsltn/index.ts +++ b/apps/as/src/entities/fnrs-cnsltn/index.ts @@ -3,8 +3,11 @@ export { fnrsCnsltnKeys } from "./api/queries"; export { useChangePrgrsSttsComCd, useDeleteFnrsCnsltnMng, + useFnrsCnsltnFileVrfcResults, useFnrsCnsltnMng, useFnrsCnsltnMngPage, + useRequestActnReviewFnrsCnsltnMng, + useRequestExamineFnrsCnsltnMng, useSaveApplyFnrsCnsltnMng, useSaveFnrsCnsltnMng, useSubmitReqSupplementFnrsCnsltnMng, @@ -25,6 +28,7 @@ export type { EsntlAtchFileItem, EsntlAtchFileMngTreeResponseDto, FnrsCnsltnApplySaveRequestDto, + FnrsCnsltnFileVrfcRsltResponseDto, FnrsCnsltnMngDetResponseDto, FnrsCnsltnMngResponseDto, FnrsCnsltnMngSaveRequestDto, @@ -37,3 +41,11 @@ export type { FnrsCnsltnSplmntDmndResponseDto, FnrsSharItem, } from "./model/fnrs-cnsltn-interface"; +export type { + EnvoActnReviewReqDto, + FnrsExamineRequestDto, +} from "./model/fnrs-cnsltn-payload-schema"; +export { + envoActnReviewReqSchema, + fnrsExamineRequestSchema, +} from "./model/fnrs-cnsltn-payload-schema"; diff --git a/apps/as/src/entities/fnrs-cnsltn/model/fnrs-cnsltn-interface.ts b/apps/as/src/entities/fnrs-cnsltn/model/fnrs-cnsltn-interface.ts index 44045341d..8e50d5d79 100644 --- a/apps/as/src/entities/fnrs-cnsltn/model/fnrs-cnsltn-interface.ts +++ b/apps/as/src/entities/fnrs-cnsltn/model/fnrs-cnsltn-interface.ts @@ -16,6 +16,11 @@ import type { } from "@/shared/model"; import type { FnrsSharBizCstTreeDto } from "@/entities/fnrs-shar-se"; +import type { + EnvoActnReviewReqDto, + FnrsExamineRequestDto, +} from "./fnrs-cnsltn-payload-schema"; + export type { AtflMngClientResponseDto, BizCstTreeDto, @@ -79,6 +84,8 @@ export interface FnrsCnsltnMngSearchDto extends PageableParams { atchFileGroupId?: string; sharAtchFileGroupId?: string; prgrsSttsComCd?: string; + rtlztnFcltSeComCd?: string; + rtlztnUsgSeComCd?: string; } interface FnrsCnsltnMngResponseExtension { @@ -86,6 +93,10 @@ interface FnrsCnsltnMngResponseExtension { envoSeCdNm?: string; taskSeCdNm?: string; prgrsSttsCdNm?: string; + beforePrgrsSttsComCd?: string; + beforePrgrsSttsCdNm?: string; + rtlztnFcltSeComNm?: string; + rtlztnUsgSeComNm?: string; regDt?: string; rgtr?: string; rgtrNm?: string; @@ -163,6 +174,22 @@ export interface FnrsCnsltnApplySaveRequestDto extends PbadmsApplySaveHeader { fnrsSharList?: FnrsSharItem[]; } +/** 백엔드 FnrsCnsltnFileVrfcRsltResponseDto */ +export interface FnrsCnsltnFileVrfcRsltResponseDto { + fileSeComCd?: string; + fileSeNm?: string; + esntlAtchFileId?: string; + atchFileGroupId?: string; + atflId?: string; + orgnlFileNm?: string; + atflFlieSz?: number; + vrfcSttsComCd?: string; + vrfcSttsComNm?: string; + vrfcRsltCn?: string; + vrfcDt?: string; + regDt?: string; +} + /** Controller public 메서드명·시그니처와 동일 */ export interface FnrsCnsltnMngService { findPage(searchDto: FnrsCnsltnMngSearchDto): Promise>; @@ -171,8 +198,11 @@ export interface FnrsCnsltnMngService { saveApply(body: FnrsCnsltnApplySaveRequestDto): Promise; update(fnrsCnsltnDocNo: string, body: FnrsCnsltnMngUpdateRequestDto): Promise; techReview(id: string, body: FnrsCnsltnApplySaveRequestDto): Promise; + requestExamine(docNo: string, body: FnrsExamineRequestDto): Promise; + requestActnReview(docNo: string, body: EnvoActnReviewReqDto): Promise; submitSupplement(id: string, body: FnrsCnsltnApplySaveRequestDto): Promise; submitReqSupplement(id: string, body: FnrsCnsltnApplySaveRequestDto): Promise; remove(fnrsCnsltnDocNo: string): Promise; + findFileVrfcResults(fnrsCnsltnDocNo: string): Promise; changePrgrsSttsComCd(body: DocPrgrsUpdateRequestDto): Promise; } diff --git a/apps/as/src/entities/fnrs-cnsltn/model/fnrs-cnsltn-payload-schema.ts b/apps/as/src/entities/fnrs-cnsltn/model/fnrs-cnsltn-payload-schema.ts new file mode 100644 index 000000000..a34b22ad6 --- /dev/null +++ b/apps/as/src/entities/fnrs-cnsltn/model/fnrs-cnsltn-payload-schema.ts @@ -0,0 +1,15 @@ +import { z } from "zod"; + +/** 백엔드 FnrsExamineRequestDto */ +export const fnrsExamineRequestSchema = z.object({ + prgrsSttsComCd: z.string().optional(), +}); + +/** 백엔드 EnvoActnReviewReqDto */ +export const envoActnReviewReqSchema = z.object({ + envoDocNo: z.string().min(1), + specialRqstCn: z.string().optional(), +}); + +export type FnrsExamineRequestDto = z.infer; +export type EnvoActnReviewReqDto = z.infer; diff --git a/apps/as/src/pages/fnrs-cnsltn/ui/components/floating-action-buttons.tsx b/apps/as/src/pages/fnrs-cnsltn/ui/components/floating-action-buttons.tsx index 67666c48e..81fce4fc4 100644 --- a/apps/as/src/pages/fnrs-cnsltn/ui/components/floating-action-buttons.tsx +++ b/apps/as/src/pages/fnrs-cnsltn/ui/components/floating-action-buttons.tsx @@ -25,6 +25,7 @@ import { fnrsCnsltnKeys, type FnrsCnsltnMngDetResponseDto, fnrsCnsltnMngService, + type FnrsExamineRequestDto, } from "@/entities/fnrs-cnsltn"; import { SplmntDmndDialog, type SplmntDmndDialogConfirmPayload } from "@/widgets/pbadms-sprt"; import { Button } from "@common/components"; @@ -299,10 +300,8 @@ function FloatingActionButtons({ } async function handleRqstTechRvwClick() { - const payload: DocPrgrsUpdateRequestDto = { - docNo, - docSeComCd, - prgrsSttsComCd: "ER", + const payload: FnrsExamineRequestDto = { + prgrsSttsComCd: "FV", }; await executeAction({ action: FNRS_CNSLTN_VIEW_BUTTON_ACTION.rqstTechRvw, @@ -602,6 +601,19 @@ async function handleDmndSplmnt( } } +async function handleRequestExamine( + context: ActionHandlerContext, +): Promise { + try { + const docNo = context.data.detDto?.fnrsCnsltnDocNo; + if (!docNo) throw new Error("문서번호가 없습니다."); + await fnrsCnsltnMngService.requestExamine(docNo, context.request); + context.onSuccess?.(); + } catch (error) { + context.onError?.(error as Error); + } +} + async function handleAtrzAprv(context: ActionHandlerContext): Promise { // TODO: 결재 승인 처리 API 호출 context.onSuccess?.(); @@ -621,7 +633,7 @@ const buttonActionHandlers: Record = rjct: handleChangePrgrsSttsComCd, sncnAprv: handleChangePrgrsSttsComCd, rvwRply: handleTechReview, - rqstTechRvw: handleChangePrgrsSttsComCd, + rqstTechRvw: handleRequestExamine, fileVrfc: () => Promise.resolve(), dsgntRvwr: handleDsgntRvwr, pwrkCnsltnDocCrt: () => Promise.resolve(), diff --git a/apps/as/src/widgets/pbadms-sprt/ui/attachments-form-section.tsx b/apps/as/src/widgets/pbadms-sprt/ui/attachments-form-section.tsx index 816c3e6b7..ff62679b6 100644 --- a/apps/as/src/widgets/pbadms-sprt/ui/attachments-form-section.tsx +++ b/apps/as/src/widgets/pbadms-sprt/ui/attachments-form-section.tsx @@ -456,11 +456,12 @@ function AttachmentsFormSection({ )}
-