From 5e54039028393c4b58e62a60ce9288a7da2e15b2 Mon Sep 17 00:00:00 2001 From: bicochan Date: Tue, 15 Sep 2026 16:42:21 +0900 Subject: [PATCH 01/20] =?UTF-8?q?[as]=20feat:=20=EC=8B=A4=EB=AC=B4?= =?UTF-8?q?=ED=98=91=EC=9D=98=EC=84=9C=20=EA=B2=80=ED=86=A0=EC=9E=90=20?= =?UTF-8?q?=EC=A7=80=EC=A0=95(EV)=20=EB=A1=9C=EC=A7=81=20=EC=9E=91?= =?UTF-8?q?=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/as/docs/pwrk-cnsltn/development-guide.md | 71 +++++----- apps/as/docs/pwrk-cnsltn/ref-endpoint.md | 10 +- .../docs/pwrk-cnsltn/ref-frontend-entities.md | 5 +- .../as/docs/pwrk-cnsltn/ref-process-status.md | 26 ++-- .../as/docs/pwrk-cnsltn/ref-screen-buttons.md | 8 +- .../entities/elapr/api/elapr-dmnd-service.ts | 6 +- apps/as/src/entities/elapr/api/queries.ts | 21 ++- apps/as/src/entities/elapr/index.ts | 5 + .../elapr/lib/doc-prgrs-to-apln-rows.ts | 21 +++ .../src/entities/elapr/lib/use-apln-rows.ts | 14 +- .../elapr/model/elapr-dmnd-interface.ts | 2 +- .../elapr/ui/elapr-apln-picker-grid.tsx | 33 +++-- .../ui/elapr-doc-prgrs-picker-dialog.tsx | 129 ++++++++++++++++++ .../elapr/ui/elapr-doc-prgrs-status.tsx | 84 +++++++++--- .../pages/fnrs-cnsltn/lib/button-config.ts | 10 +- .../ui/components/floating-action-buttons.tsx | 54 ++++++-- apps/as/src/shared/model/pbadms-sprt.ts | 1 + 17 files changed, 385 insertions(+), 115 deletions(-) create mode 100644 apps/as/src/entities/elapr/lib/doc-prgrs-to-apln-rows.ts create mode 100644 apps/as/src/entities/elapr/ui/elapr-doc-prgrs-picker-dialog.tsx diff --git a/apps/as/docs/pwrk-cnsltn/development-guide.md b/apps/as/docs/pwrk-cnsltn/development-guide.md index 6812c3db1..08193cd83 100644 --- a/apps/as/docs/pwrk-cnsltn/development-guide.md +++ b/apps/as/docs/pwrk-cnsltn/development-guide.md @@ -10,7 +10,7 @@ > > - 프로세스·상태·버튼: `03.재원협의_실무협의_프로세스_통합_v완결.md` > - REST 설계: `05.재원협의_상태별_endpoint_설계.md` -> - 공통코드: `FNRSSTTS` (`SV, ST, LE, FV, ER, SL, AC, TE, TP, RM, RB, RC, RA, AV, RK, RR, EP, TA`) +> - 공통코드: `FNRSSTTS` (`SV, ST, LE, FV, ER, SL, AC, TE, TP, RM, RB, RC, RA, AV, EV, RK, RR, EP, TA`) > > **백엔드 서비스**: > @@ -40,7 +40,7 @@ v1.0은 공단 접수자의 **자료검증 → 초안생성 → 웹기안기** | [ref-screen-buttons.md](./ref-screen-buttons.md) | 38행 화면·역할·버튼 매트릭스, 버튼 가시성 | `button-config.ts` 개편 | | [ref-endpoint.md](./ref-endpoint.md) | 버튼→API 총괄, 단계별 입출력, FE 호출 금지 API, Gap Analysis | 엔티티·service 매핑 | | [ref-frontend-entities.md](./ref-frontend-entities.md) | ENDPOINT, 슬라이스, Service 시그니처, 폴링, 웹기안기, DTO | 엔티티 레이어 구현 | -| [ref-webhwp-api.md](./ref-webhwp-api.md) | 웹한글기안기 v3 `HwpCtrl` Properties/Methods, Open/SaveAs | 기안기 위젯 연동 | +| [ref-webhwp-api.md](./ref-webhwp-api.md) | 웹한글기안기 v3 `HwpCtrl` Properties/Methods, Open/SaveAs | 기안기 위젯 연동 | --- @@ -98,7 +98,7 @@ v1.0은 공단 접수자의 **자료검증 → 초안생성 → 웹기안기** 정방향: ``` -SV → ST → LE → FV → ER → AC → TE → TP → RM → RB → RC → RA → AV → RK → RR → EP → TA +SV → ST → LE → FV → ER → AC → TE → TP → RM → RB → RC → RA → AV → EV → RK → RR → EP → TA ``` 자체종결: `LE → EP → TA` @@ -119,7 +119,8 @@ SV → ST → LE → FV → ER → AC → TE → TP → RM → RB → RC → RA | `RB` | 지자체회신 | 기초 실무협의서 관리 / 조치완료 | | `RC` | 조치결과서 제출 | 광역 → 환경청 `RA` | | `RA` | 조치결과서제출(환경청) | 환경청 2차 의뢰 `AV` | -| `AV` | 금액검증 | AI 진행 표시. **30분** 후 `RK` Fallback | +| `AV` | 금액검증 | AI 진행 표시. **30분** 후 `EV` Fallback | +| `EV` | 조치결과검토의뢰 | 공단 접수자: 2차 결재선 검토자지정 → `RK` | | `RK` | 조치결과서검토 | 웹기안기·금액검증 재실행·보완. 결재선 2차 | | `RR` | 조치결과서검토 회신 | 환경청 → 광역 `EP` | | `EP` | 검토결과 회신 | 광역 → 기초 `TA` | @@ -144,7 +145,7 @@ SV → ST → LE → FV → ER → AC → TE → TP → RM → RB → RC → RA 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으로 처리한다. -9. **2차 결재선 복사는 백엔드**. `POST /elapr-apln/copy-line`은 `AV→RK` 콜백에서 호출한다. 프론트는 `RK`에서 2차 결재선을 **조회·표시**만 한다. +9. **2차 결재선은 EV에서 수동 검토자지정**. `POST /elapr-dmnd` (`elaprCycl: 2`, `docPrgrsSttsComCd: RK`). 1차 결재선 자동 copy-line은 사용하지 않는다. 10. **웹기안기는 `webhwp/open` 응답을 axios `blob`으로 조회한 뒤 `File`로 감싸 `HwpCtrl.Open`에 전달한다.** `blob:` Object URL과 `orgnlOtptDocCn`은 쓰지 않는다. --- @@ -189,6 +190,7 @@ BEGIN ON [파일보완] (ER, ATRZ01) → GET file-vrfc-results → 팝업 → reqsupplement ON [파일검증] (ER, ATRZ01) → dcrag-to transfer (상태 유지) ON [검토자지정] (ER, ATRZ01) → POST elapr-dmnd (docPrgrsSttsComCd: AC) → START POLL AC + ON [검토자지정] (EV, ATRZ01) → POST elapr-dmnd (elaprCycl: 2, docPrgrsSttsComCd: RK) ON [실무협의서관리] (TE|RK) → GET webhwp/open (blob) → HwpCtrl.Open(File) ON [실무협의서생성] (TE, 실패/타임아웃) → dcrag-to draft/generate ON [검토결과조회] (TE) → pwrk-cnsltn-mng findById | findByUpDocNo @@ -212,36 +214,37 @@ 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` | -| 환경청 | 결과회신(자체종결) | `LE→EP` | `POST /fnrs-cnsltn-mng/{docNo}/tech-review` | -| 환경청 | 기술검토 의뢰 | `LE→FV` | **신규** `POST /fnrs-cnsltn-mng/{docNo}/request-examine` | -| 공단 접수 | 파일보완 팝업 | `ER` | `GET /fnrs-cnsltn-mng/{docNo}/file-vrfc-results` | -| 공단 접수 | 파일보완요청 | `ER→SL` | `POST /fnrs-cnsltn-mng/{docNo}/reqsupplement` | -| 공단 접수 | 파일검증 재실행 | `ER` 유지 | `POST /dcrag-to/documents/transfer` | -| 공단 접수 | 검토자지정 | `ER→AC` | `POST /elapr-dmnd` | -| 공단 검토 | 실무협의서관리 | `TE`/`RK` | `GET .../pwrk-cnsltn-doc-crt-rslt/{uuid}/webhwp/open` | -| 공단 검토 | 실무협의서생성 | `TE` 유지 | `POST /dcrag-to/documents/draft/generate` | -| 공단 검토 | 저장 | `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` | -| 환경청 | 재원협의 결과 회신 | `TP→RM` | `POST /fnrs-cnsltn-mng/{docNo}/tech-review` | -| 광역 | 지자체회신 | `RM→RB` | `updatePrgrsStts` | -| 기초 | 실무협의서 관리 | `RB` 유지 | `GET .../pwrk-cnsltn-doc-crt-rslt/{uuid}/webhwp/open` | +| 주체 | 버튼 | 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` | +| 환경청 | 결과회신(자체종결) | `LE→EP` | `POST /fnrs-cnsltn-mng/{docNo}/tech-review` | +| 환경청 | 기술검토 의뢰 | `LE→FV` | **신규** `POST /fnrs-cnsltn-mng/{docNo}/request-examine` | +| 공단 접수 | 파일보완 팝업 | `ER` | `GET /fnrs-cnsltn-mng/{docNo}/file-vrfc-results` | +| 공단 접수 | 파일보완요청 | `ER→SL` | `POST /fnrs-cnsltn-mng/{docNo}/reqsupplement` | +| 공단 접수 | 파일검증 재실행 | `ER` 유지 | `POST /dcrag-to/documents/transfer` | +| 공단 접수 | 검토자지정 | `ER→AC` | `POST /elapr-dmnd` (`elaprCycl: 1`) | +| 공단 접수 | 검토자지정 | `EV→RK` | `POST /elapr-dmnd` (`elaprCycl: 2`) | +| 공단 검토 | 실무협의서관리 | `TE`/`RK` | `GET .../pwrk-cnsltn-doc-crt-rslt/{uuid}/webhwp/open` | +| 공단 검토 | 실무협의서생성 | `TE` 유지 | `POST /dcrag-to/documents/draft/generate` | +| 공단 검토 | 저장 | `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` | +| 환경청 | 재원협의 결과 회신 | `TP→RM` | `POST /fnrs-cnsltn-mng/{docNo}/tech-review` | +| 광역 | 지자체회신 | `RM→RB` | `updatePrgrsStts` | +| 기초 | 실무협의서 관리 | `RB` 유지 | `GET .../pwrk-cnsltn-doc-crt-rslt/{uuid}/webhwp/open` | | 기초 | 조치완료 | `RB→RA` | **신규** `POST /pwrk-cnsltn-mng/{pwrkDocNo}/submit-actn-result` (`isSubmit: true`) | -| 광역 | 조치결과서제출 | `RC→RA` | `updatePrgrsStts` | -| 환경청 | 실무협의서 관리 | `RA` 유지 (조회) | `GET .../pwrk-cnsltn-doc-crt-rslt/{uuid}/webhwp/open` | -| 환경청 | 조치결과 검토의뢰 | `RA→AV` | **신규** `POST /fnrs-cnsltn-mng/{docNo}/request-actn-review` | -| 공단 검토 | 금액검증 재실행 | `RK` 유지 | `POST /dcrag-to/documents/cost/verify` | -| 환경청 | 결과회신 | `RR→EP` | `updatePrgrsStts` | -| 광역 | 결과회신 | `EP→TA` | `updatePrgrsStts` | -| 웹기안기 | 저장 | 버전 +1 | `POST /pwrk-cnsltn-doc-crt-rslt` multipart | -| 공통 | 다운로드 | — | `GET /pwrk-cnsltn-doc-crt-rslt/{uuid}/download` | +| 광역 | 조치결과서제출 | `RC→RA` | `updatePrgrsStts` | +| 환경청 | 실무협의서 관리 | `RA` 유지 (조회) | `GET .../pwrk-cnsltn-doc-crt-rslt/{uuid}/webhwp/open` | +| 환경청 | 조치결과 검토의뢰 | `RA→AV` | **신규** `POST /fnrs-cnsltn-mng/{docNo}/request-actn-review` | +| 공단 검토 | 금액검증 재실행 | `RK` 유지 | `POST /dcrag-to/documents/cost/verify` | +| 환경청 | 결과회신 | `RR→EP` | `updatePrgrsStts` | +| 광역 | 결과회신 | `EP→TA` | `updatePrgrsStts` | +| 웹기안기 | 저장 | 버전 +1 | `POST /pwrk-cnsltn-doc-crt-rslt` multipart | +| 공통 | 다운로드 | — | `GET /pwrk-cnsltn-doc-crt-rslt/{uuid}/download` | -신규 4개: `request-examine`, `submit-actn-result`, `request-actn-review`, (백엔드) `elapr-apln/copy-line`. +신규 4개: `request-examine`, `submit-actn-result`, `request-actn-review`, EV 2차 `elapr-dmnd`. --- diff --git a/apps/as/docs/pwrk-cnsltn/ref-endpoint.md b/apps/as/docs/pwrk-cnsltn/ref-endpoint.md index d63d2d4de..712ae57d6 100644 --- a/apps/as/docs/pwrk-cnsltn/ref-endpoint.md +++ b/apps/as/docs/pwrk-cnsltn/ref-endpoint.md @@ -43,7 +43,8 @@ | 27 | 조치완료 | `RB→RA` | as | `POST /api/v1/pwrk-cnsltn-mng/{pwrkDocNo}/submit-actn-result` (`isSubmit=true`) | **신규** | | 28 | 조치결과서제출 | `RC→RA` | as | `updatePrgrsStts` | 기존 | | 29 | 조치결과 검토의뢰 | `RA→AV` | as | `POST /api/v1/fnrs-cnsltn-mng/{docNo}/request-actn-review` | **신규** | -| 30 | 금액검증 콜백 | `AV→RK` | as | `POST /api/v1/dcrag/cost/verify-result` | 서버 | +| 30 | 금액검증 콜백 | `AV→EV` | as | `POST /api/v1/dcrag/cost/verify-result` | 서버 | +| 30a | 검토자지정(2차) | `EV→RK` | elapr | `POST /api/v1/elapr-dmnd` (`elaprCycl=2`) | 기존 | | 31 | 실무협의서관리 | `RK` | as | `GET /pwrk-cnsltn-mng/{pwrkDocNo}` | 기존 | | 32 | 금액검증 재실행 | `RK` | as | `POST /api/v1/dcrag-to/documents/cost/verify` | 기존 | | 33 | 보완요청(금액) | `RK→SL` | as | `reqsupplement` | 기존 | @@ -212,7 +213,7 @@ v1.0 가이드의 “이 API를 프론트가 치면 안 된다”는 **폐기**. - `isSubmit: true` → `RB→RA` (조치완료) 응답: `string` (pwrkDocNo). DTO명 `PwrkActnResultSubmitDto`. -### 3-6. `RA → AV → RK` +### 3-6. `RA → AV → EV → RK` **2차 의뢰 (신규)** — `POST /fnrs-cnsltn-mng/{docNo}/request-actn-review` ```json @@ -223,7 +224,8 @@ v1.0 가이드의 “이 API를 프론트가 치면 안 된다”는 **폐기**. `RA→AV`. 응답: `string` (docNo). DTO명 `EnvoActnReviewReqDto`. `specialRqstCn`만 선택. -금액검증 콜백은 서버. 콜백 후 서버가 `copy-line` 호출. +금액검증 콜백은 서버 → `AV→EV`. +**2차 검토자지정** — `POST /elapr-dmnd` (`elaprCycl: 2`, `docPrgrsSttsComCd: RK`). 1차 결재선(`findDocPrgrsByDocNo`, cycl=1)을 시드로 편집. **금액검증 재실행** — `POST /dcrag-to/documents/cost/verify` @@ -292,7 +294,7 @@ multipart `Content-Type` 헤더를 수동 지정하지 않는다 (boundary). JSO } ``` -`RK`에서 2차 결재선은 기존 `findDocPrgrsByDocNo` / `elaprCycl=2` 조회로 표시. +`RK`에서 결재현황은 `findDocPrgrsByDocNo`(전체) 조회 후 `elaprCycl`로 1차/2차 탭 표시. --- diff --git a/apps/as/docs/pwrk-cnsltn/ref-frontend-entities.md b/apps/as/docs/pwrk-cnsltn/ref-frontend-entities.md index e63531842..ddb0f5f3d 100644 --- a/apps/as/docs/pwrk-cnsltn/ref-frontend-entities.md +++ b/apps/as/docs/pwrk-cnsltn/ref-frontend-entities.md @@ -343,5 +343,6 @@ docPrgrsSttsComCd: data.detDto?.prgrsSttsComCd, // ER To-Be: -- 검토자지정은 **`ER`에서만**. `elaprCycl: 1`, `docPrgrsSttsComCd: "AC"` -- 2차 결재선은 서버 `copy-line`. `RK`에서 검토자지정 팝업을 다시 열지 않음 +- 검토자지정은 **`ER`(1차)** 과 **`EV`(2차)** 에서. +- `ER`: `elaprCycl: 1`, `docPrgrsSttsComCd: "AC"`, 서식 선택 다이얼로그 +- `EV`: `elaprCycl: 2`, `docPrgrsSttsComCd: "RK"`, 1차 결재선 시드 다이얼로그(서식 없음) diff --git a/apps/as/docs/pwrk-cnsltn/ref-process-status.md b/apps/as/docs/pwrk-cnsltn/ref-process-status.md index e5da682d3..d5d55171b 100644 --- a/apps/as/docs/pwrk-cnsltn/ref-process-status.md +++ b/apps/as/docs/pwrk-cnsltn/ref-process-status.md @@ -16,7 +16,7 @@ 2-Pass: - **Pass 1** 기술 타당성: `SV→ST→LE→FV→ER→AC→TE→TP→RM→RB` -- **Pass 2** 조치결과·금액: `RB→RA→AV→RK→RR→EP→TA` +- **Pass 2** 조치결과·금액: `RB→RA→AV→EV→RK→RR→EP→TA` 자체종결(기술검토 생략): `LE→EP→TA` @@ -80,9 +80,9 @@ sequenceDiagram rect rgb(240, 255, 255) 광역->>환경청: [조치결과서제출] RC → RA 환경청->>AI: [조치결과 검토의뢰] RA → AV - AI-->>공단: 금액검증 콜백 AV → RK - Note over 공단: 30분 미응답 시 RK + 수동 [금액검증] - Note over 공단: AV→RK 시 1차 결재선 → 2차 복사 (서버) + AI-->>공단: 금액검증 콜백 AV → EV + 공단->>공단: [검토자지정] EV → RK + Note over 공단: EV에서 1차 결재선 시드로 2차 결재선 수동 배정 end rect rgb(255, 255, 230) @@ -125,7 +125,8 @@ sequenceDiagram | 9 | 검토결과 회신 | 환경청·광역 | `TP→RM→RB` | 1차 회신. `EP`와 혼동 금지 | | 10 | 조치결과 작성 | 기초 | `RB→RA` | `submit-actn-result` `isSubmit:true` (조치완료) | | 11 | 조치 의뢰 | 환경청 | `RA→AV` | `request-actn-review` | -| 12 | AI 금액검증 | AI·공단 | `AV→RK` | 결재선 복사(서버) | +| 12 | AI 금액검증 | AI·공단 | `AV→EV` | 콜백/Fallback 후 접수자 대기 | +| 12a | 2차 검토자지정 | 공단 접수 | `EV→RK` | `elapr-dmnd` cycl=2 | | 13 | 2차 검토·결재 | 공단 | `RK→RR` / `SL` | 2차 결재선 | | 14 | 최종 회신 | 환경청·광역·기초 | `RR→EP→TA` | 종결 | @@ -151,7 +152,8 @@ sequenceDiagram | `RC` | 조치결과서 제출 | Result Complete | 기초→광역 | `RB→RC` | | `RA` | 조치결과서 제출(환경청) | Result Ask to Basin | 기초→환경청 | `RB→RA` | | `AV` | 금액검증 | Amount Verification | AI | `RA→AV` | -| `RK` | 조치결과서검토 | Result Check | 공단 2차 결재 | `AV→RK`, `SL→RK` | +| `EV` | 조치결과검토의뢰 | Examine Verify | 공단 접수자 | `AV→EV` | +| `RK` | 조치결과서검토 | Result Check | 공단 2차 결재 | `EV→RK`, `SL→RK` | | `RR` | 조치결과서검토 회신 | Result Return to Basin | 공단→환경청 | `RK→RR` | | `EP` | 검토결과 회신 | Examine Pass to Province | 환경청→광역 | `LE→EP`(자체), `RR→EP`(최종) | | `TA` | 검토결과 회신(종료) | Technical Approval | 광역→기초 | `EP→TA` | @@ -200,7 +202,7 @@ stateDiagram-v2 | --- | --- | --- | --- | --- | --- | | AI-1 | 파일 무결성 | `FV→ER` | 환경청 [기술검토 의뢰] | 30분 → `ER` + [파일검증] | `POST /dcrag-to/documents/transfer` | | AI-2 | 초안 생성 | `AC→TE` | 공단 [검토자지정] | 30분 → `TE` + [실무협의서생성] | `POST /dcrag-to/documents/draft/generate` | -| AI-3 | 금액 검증 | `AV→RK` | 환경청 [조치결과 검토의뢰] | 30분 → `RK` + [금액검증] | `POST /dcrag-to/documents/cost/verify` | +| AI-3 | 금액 검증 | `AV→EV` | 환경청 [조치결과 검토의뢰] | 30분 → `EV` + 수동 [금액검증] | `POST /dcrag-to/documents/cost/verify` | - 예상 소요 안내는 **30분** (v1.0의 10분은 폐기). - 콜백 수신·스케줄러 전이는 서버. FE는 상세 refetch / draft status 폴링만. @@ -221,14 +223,12 @@ stateDiagram-v2 --- -## 7. 결재선 복사 - -규칙: `"금액검증후: 2차결재선 1차결재선 복사생성"` +## 7. 2차 결재선 (수동 검토자지정) 1. `TE`에서 1차 결재선(`elaprCycl = 1`) 완료. -2. `AV→RK` 콜백 시 서버가 `POST /elapr-apln/copy-line` (`source=1`, `target=2`). -3. `RK` 화면은 2차 결재선을 조회해 검토자/승인자/최종승인자를 표시. -4. 프론트는 copy-line을 **호출하지 않는다.** +2. 금액검증 콜백/Fallback → `AV→EV`. +3. 공단 접수자가 `EV`에서 [검토자지정]: 1차 결재선을 시드로 편집 후 `POST /elapr-dmnd` (`elaprCycl: 2`) → `RK`. +4. `copy-line` 자동 복사는 사용하지 않는다. 결재 `process`: diff --git a/apps/as/docs/pwrk-cnsltn/ref-screen-buttons.md b/apps/as/docs/pwrk-cnsltn/ref-screen-buttons.md index a500fad11..1c9d8565d 100644 --- a/apps/as/docs/pwrk-cnsltn/ref-screen-buttons.md +++ b/apps/as/docs/pwrk-cnsltn/ref-screen-buttons.md @@ -62,7 +62,8 @@ API 컬럼은 [ref-endpoint.md](./ref-endpoint.md)와 동일. | 27 | 상세 | USER04 | - | `RC` | 조치결과서제출 | `RA` | 환경청 | `updatePrgrsStts` | | 28 | 상세 | USER03 | - | `RA` | 실무협의서 관리 | 유지 | — | 웹기안기 Open. **저장 불가** | | 28a | 상세 | USER03 | - | `RA` | 조치결과 검토의뢰 | `AV` | 공단 검토 | **`request-actn-review`** | -| 29 | 자동화 | AI | - | `AV` | (금액검증) | `RK` | 공단 검토 | FE 호출 없음. 진행 패널 | +| 29 | 자동화 | AI | - | `AV` | (금액검증) | `EV` | 공단 접수 | FE 호출 없음. 진행 패널 | +| 29a | 상세 | USER01 | 접수자 | `EV` | 검토자지정 | `RK` | 공단 검토 | `POST /elapr-dmnd` cycl=2. 1차 결재선 시드 | | 30 | 상세 | USER01 | 검토자 | `RK` | 실무협의서관리 | 유지 | — | 웹기안기 | | 31 | 상세 | USER01 | 검토자 | `RK` | 금액검증 | `RK` | — | `dcrag-to/cost/verify` | | 32 | 상세 | USER01 | 검토자 | `RK` | 저장 | `RK` | — | `pwrk save-apply` | @@ -85,7 +86,7 @@ API 컬럼은 [ref-endpoint.md](./ref-endpoint.md)와 동일. | --- | --- | --- | | `fileSplmnt` | 파일보완 | `ER` 접수자. 현행에 없음 | | `fileVrfc` | 파일검증 | 유지. `ER` 재실행 | -| `dsgntRvwr` | 검토자지정 | 유지. 전이를 `AC`로 | +| `dsgntRvwr` | 검토자지정 | `ER→AC`(1차), `EV→RK`(2차) | | `pwrkCnsltnDocMng` | 실무협의서관리 | 유지. `TE`·`RK`·`RB`·`RA`(조회 전용) | | `pwrkCnsltnDocCrt` | 실무협의서생성 | 유지. 실패/타임아웃만 | | `rvwRsltInq` | 검토결과조회 | 신규 | @@ -129,6 +130,9 @@ ROLE_USER03 ER / ATRZ01 접수자 → 파일보완, 파일검증, 검토자지정 +EV / ATRZ01 접수자 + → 검토자지정 (2차 결재선. 1차 결재선 시드, 서식 선택 없음) + TE / ATRZ02 검토자 → (초안 성공) 실무협의서관리, 검토결과조회, 저장, 검토완료, 보완요청 → (초안 실패·타임아웃) 실무협의서생성 (+ 위 항목 중 관리/조회는 초안 생긴 뒤) diff --git a/apps/as/src/entities/elapr/api/elapr-dmnd-service.ts b/apps/as/src/entities/elapr/api/elapr-dmnd-service.ts index 368600110..b366afb60 100644 --- a/apps/as/src/entities/elapr/api/elapr-dmnd-service.ts +++ b/apps/as/src/entities/elapr/api/elapr-dmnd-service.ts @@ -49,9 +49,13 @@ async function remove(elaprDmndId: string): Promise { await client.delete(`${BASE}/${elaprDmndId}`); } -async function findDocPrgrsByDocNo(elaprDocNo: string): Promise { +async function findDocPrgrsByDocNo( + elaprDocNo: string, + elaprCycl?: number, +): Promise { const response = await client.get( `${BASE}/sanc/docprgrs/${elaprDocNo}`, + { params: elaprCycl != null ? { elaprCycl } : undefined }, ); return response.data; } diff --git a/apps/as/src/entities/elapr/api/queries.ts b/apps/as/src/entities/elapr/api/queries.ts index 734c6cdf4..19f5fce9b 100644 --- a/apps/as/src/entities/elapr/api/queries.ts +++ b/apps/as/src/entities/elapr/api/queries.ts @@ -185,11 +185,15 @@ export function useElaprDmnd(elaprDmndId: string | null | undefined) { }); } -export function useElaprDocPrgrsByDocNo(elaprDocNo: string | null | undefined) { +export function useElaprDocPrgrsByDocNo( + elaprDocNo: string | null | undefined, + options?: { elaprCycl?: number; enabled?: boolean }, +) { + const elaprCycl = options?.elaprCycl; return useQuery({ - queryKey: [...elaprDmndBaseKey, "findDocPrgrsByDocNo", elaprDocNo], - queryFn: () => elaprDmndService.findDocPrgrsByDocNo(elaprDocNo!), - enabled: Boolean(elaprDocNo), + queryKey: [...elaprDmndBaseKey, "findDocPrgrsByDocNo", elaprDocNo, elaprCycl], + queryFn: () => elaprDmndService.findDocPrgrsByDocNo(elaprDocNo!, elaprCycl), + enabled: Boolean(elaprDocNo) && (options?.enabled ?? true), }); } @@ -284,13 +288,8 @@ export function useProcessElaprPrgrsStts() { const queryClient = useQueryClient(); return useMutation({ - mutationFn: ({ - elaprPrgrsId, - body, - }: { - elaprPrgrsId: string; - body: ElaprProcessRequestDto; - }) => elaprPrgrsSttsService.process(elaprPrgrsId, body), + mutationFn: ({ elaprPrgrsId, body }: { elaprPrgrsId: string; body: ElaprProcessRequestDto }) => + elaprPrgrsSttsService.process(elaprPrgrsId, body), onSuccess: () => { invalidateElaprPrgrsSttsQueries(queryClient); }, diff --git a/apps/as/src/entities/elapr/index.ts b/apps/as/src/entities/elapr/index.ts index 4805fecc3..777245649 100644 --- a/apps/as/src/entities/elapr/index.ts +++ b/apps/as/src/entities/elapr/index.ts @@ -57,6 +57,7 @@ export { buildElaprPrgrsSttsListFromApln, buildElaprPrgrsSttsListFromAplnRows, } from "./lib/dmnd-save-utils"; +export { mapDocPrgrsToAplnRows } from "./lib/doc-prgrs-to-apln-rows"; export type { ElaprPrgrsSttsRow } from "./lib/prgrs-stts-save-utils"; export { assignPrgrsSttsAtrzSeqNumbers, @@ -113,6 +114,10 @@ export type { ReviewerOption } from "./model/reviewer-option"; export { AprvrPickerDialog } from "./ui/aprvr-picker-dialog"; export { ElaprAplnPickerGrid } from "./ui/elapr-apln-picker-grid"; export { ElaprApprovalDialog } from "./ui/elapr-approval-dialog"; +export { + type ElaprDocPrgrsPickerConfirmPayload, + ElaprDocPrgrsPickerDialog, +} from "./ui/elapr-doc-prgrs-picker-dialog"; export { ElaprDocPrgrsStatus } from "./ui/elapr-doc-prgrs-status"; export { type ElaprTmpltPickerConfirmPayload, diff --git a/apps/as/src/entities/elapr/lib/doc-prgrs-to-apln-rows.ts b/apps/as/src/entities/elapr/lib/doc-prgrs-to-apln-rows.ts new file mode 100644 index 000000000..a4cf562d2 --- /dev/null +++ b/apps/as/src/entities/elapr/lib/doc-prgrs-to-apln-rows.ts @@ -0,0 +1,21 @@ +import type { ElaprDocPrgrsClientResponseDto } from "@/shared/model"; + +import type { ElaprApln } from "../model/elapr-apln-interface"; + +/** 문서 결재진행 → 결재선 그리드 시드 (ElaprApln 호환) */ +export function mapDocPrgrsToAplnRows( + list: ElaprDocPrgrsClientResponseDto[] | undefined, +): ElaprApln[] { + if (!list?.length) return []; + + return list.map((item, index) => ({ + aplnId: item.elaprPrgrsId ?? `prgrs-${item.atrzSeqNo ?? index}`, + elaprTmpltId: "", + atrzSeqNo: item.atrzSeqNo, + atrzSeComCd: item.atrzSeComCd, + atrzSeComNm: item.atrzSeComNm, + aprvrUuid: item.aprvrUuid, + aprvrNm: item.aprvrNm, + aprvrUserId: item.aprvrUserId, + })); +} diff --git a/apps/as/src/entities/elapr/lib/use-apln-rows.ts b/apps/as/src/entities/elapr/lib/use-apln-rows.ts index 384c8ffc1..dfa731d07 100644 --- a/apps/as/src/entities/elapr/lib/use-apln-rows.ts +++ b/apps/as/src/entities/elapr/lib/use-apln-rows.ts @@ -22,33 +22,35 @@ function toRow(item: ElaprApln): ElaprAplnRow { } interface UseAplnRowsOptions { - elaprTmpltId: string | null; + seedKey: string | null; serverRows: ElaprApln[] | undefined; + elaprTmpltId?: string; } export function createDraftRowKey(): string { return `draft-${Date.now()}`; } -export function useAplnRows({ elaprTmpltId, serverRows }: UseAplnRowsOptions) { +export function useAplnRows({ seedKey, serverRows, elaprTmpltId = "" }: UseAplnRowsOptions) { const [rows, setRows] = useState([]); const [editingRowKey, setEditingRowKey] = useState(null); useEffect(() => { - if (!elaprTmpltId) { + if (!seedKey) { setRows([]); setEditingRowKey(null); return; } setRows((serverRows ?? []).map(toRow)); setEditingRowKey(null); - }, [elaprTmpltId, serverRows]); + }, [seedKey, serverRows]); const isEditingLocked = editingRowKey != null; const visibleRows = getVisibleRows(rows); + const canAdd = Boolean(seedKey) && !isEditingLocked; const addRow = useCallback(() => { - if (!elaprTmpltId || isEditingLocked) return; + if (!canAdd) return; const rowKey = createDraftRowKey(); @@ -66,7 +68,7 @@ export function useAplnRows({ elaprTmpltId, serverRows }: UseAplnRowsOptions) { }, ]); setEditingRowKey(rowKey); - }, [elaprTmpltId, isEditingLocked]); + }, [canAdd, elaprTmpltId]); const startEdit = useCallback( (rowKey: string) => { diff --git a/apps/as/src/entities/elapr/model/elapr-dmnd-interface.ts b/apps/as/src/entities/elapr/model/elapr-dmnd-interface.ts index 264f45db7..5d05fd04b 100644 --- a/apps/as/src/entities/elapr/model/elapr-dmnd-interface.ts +++ b/apps/as/src/entities/elapr/model/elapr-dmnd-interface.ts @@ -45,5 +45,5 @@ export interface ElaprDmndService { update(elaprDmndId: string, body: ElaprDmndSaveRequestDto): Promise; updateStatus(elaprDmndId: string, atrzSttsComCd: string): Promise; remove(elaprDmndId: string): Promise; - findDocPrgrsByDocNo(elaprDocNo: string): Promise; + findDocPrgrsByDocNo(elaprDocNo: string, elaprCycl?: number): Promise; } diff --git a/apps/as/src/entities/elapr/ui/elapr-apln-picker-grid.tsx b/apps/as/src/entities/elapr/ui/elapr-apln-picker-grid.tsx index 92c3d58c5..7f7a88911 100644 --- a/apps/as/src/entities/elapr/ui/elapr-apln-picker-grid.tsx +++ b/apps/as/src/entities/elapr/ui/elapr-apln-picker-grid.tsx @@ -20,6 +20,7 @@ import { useElaprAplnPage } from "../api/queries"; import { validateAplnRow } from "../lib/apln-validators"; import { useAplnRows } from "../lib/use-apln-rows"; import { useDndSensors } from "../lib/use-dnd-sensors"; +import type { ElaprApln } from "../model/elapr-apln-interface"; import type { ElaprAplnRow } from "../model/elapr-apln-row-types"; import type { ReviewerOption } from "../model/reviewer-option"; @@ -27,13 +28,17 @@ import { AprvrPickerDialog } from "./aprvr-picker-dialog"; import { SortableAplnPickerRow } from "./sortable-apln-picker-row"; interface ElaprAplnPickerGridProps { - elaprTmpltId: string | null; + elaprTmpltId?: string | null; + externalServerRows?: ElaprApln[]; + isExternalLoading?: boolean; onRowsChange?: (rows: ElaprAplnRow[]) => void; onEditingLockedChange?: (locked: boolean) => void; } function ElaprAplnPickerGrid({ - elaprTmpltId, + elaprTmpltId = null, + externalServerRows, + isExternalLoading = false, onRowsChange, onEditingLockedChange, }: ElaprAplnPickerGridProps) { @@ -41,14 +46,18 @@ function ElaprAplnPickerGrid({ const [pickingRowKey, setPickingRowKey] = useState(null); const alert = useAlertStore((state) => state.setMessage); + const isExternalMode = externalServerRows != null; const aplnQuery = useElaprAplnPage({ - elaprTmpltId: elaprTmpltId ?? undefined, + elaprTmpltId: !isExternalMode ? (elaprTmpltId ?? undefined) : undefined, page: 0, size: 200, sort: "atrzSeqNo,asc", }); + const seedKey = isExternalMode ? "external-doc-prgrs" : elaprTmpltId; + const serverRows = isExternalMode ? externalServerRows : aplnQuery.data?.content; + const { rows, visibleRows, @@ -62,8 +71,9 @@ function ElaprAplnPickerGrid({ markDeleted, reorderRows, } = useAplnRows({ - elaprTmpltId, - serverRows: aplnQuery.data?.content, + seedKey, + serverRows, + elaprTmpltId: elaprTmpltId ?? "", }); useEffect(() => { @@ -75,7 +85,10 @@ function ElaprAplnPickerGrid({ }, [isEditingLocked, onEditingLockedChange]); const sensors = useDndSensors(); - const isDisabled = !elaprTmpltId; + const isReady = isExternalMode || Boolean(elaprTmpltId); + const isLoading = isExternalMode + ? isExternalLoading + : aplnQuery.isPending && Boolean(elaprTmpltId); const pickingRow = pickingRowKey ? rows.find((r) => r.rowKey === pickingRowKey) : undefined; function handleDragEnd(event: DragEndEvent) { @@ -121,7 +134,7 @@ function ElaprAplnPickerGrid({ size="sm" type="button" color="green" - disabled={isDisabled || isEditingLocked} + disabled={!isReady || isEditingLocked} onClick={addRow} > 결재선 추가 @@ -129,15 +142,15 @@ function ElaprAplnPickerGrid({ - {aplnQuery.isPending && elaprTmpltId ? ( + {isLoading ? (
- ) : !elaprTmpltId ? ( + ) : !isReady ? (

결재서식을 선택하세요.

) : visibleRows.length === 0 ? ( -

+

등록된 결재선이 없습니다. [결재선 추가]로 결재자를 등록하세요.

) : ( diff --git a/apps/as/src/entities/elapr/ui/elapr-doc-prgrs-picker-dialog.tsx b/apps/as/src/entities/elapr/ui/elapr-doc-prgrs-picker-dialog.tsx new file mode 100644 index 000000000..0d9b5161e --- /dev/null +++ b/apps/as/src/entities/elapr/ui/elapr-doc-prgrs-picker-dialog.tsx @@ -0,0 +1,129 @@ +"use client"; + +import { useCallback, useMemo, useState } from "react"; + +import { useAlertStore } from "@/shared/lib"; +import { + Button, + Dialog, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@common/components"; + +import { useElaprDocPrgrsByDocNo } from "../api/queries"; +import { + getVisibleRows, + validateAllRowsForSave, + validateAtrzOrder, + validateUniqueSeqNo, +} from "../lib/apln-validators"; +import { mapDocPrgrsToAplnRows } from "../lib/doc-prgrs-to-apln-rows"; +import type { ElaprAplnRow } from "../model/elapr-apln-row-types"; + +import { ElaprAplnPickerGrid } from "./elapr-apln-picker-grid"; + +interface ElaprDocPrgrsPickerConfirmPayload { + aplnRows: ElaprAplnRow[]; +} + +interface ElaprDocPrgrsPickerDialogProps { + open: boolean; + elaprDocNo: string; + onClose: () => void; + onConfirm?: (payload: ElaprDocPrgrsPickerConfirmPayload) => void; +} + +function ElaprDocPrgrsPickerDialog({ + open, + elaprDocNo, + onClose, + onConfirm, +}: ElaprDocPrgrsPickerDialogProps) { + const alert = useAlertStore((state) => state.setMessage); + const [aplnRows, setAplnRows] = useState([]); + const [isEditingLocked, setIsEditingLocked] = useState(false); + + const docPrgrsQuery = useElaprDocPrgrsByDocNo(elaprDocNo, { + elaprCycl: 1, + enabled: open && Boolean(elaprDocNo), + }); + + const externalServerRows = useMemo( + () => mapDocPrgrsToAplnRows(docPrgrsQuery.data), + [docPrgrsQuery.data], + ); + + const handleRowsChange = useCallback((rows: ElaprAplnRow[]) => { + setAplnRows(rows); + }, []); + + const handleEditingLockedChange = useCallback((locked: boolean) => { + setIsEditingLocked(locked); + }, []); + + function handleOpenChange(isOpen: boolean) { + if (!isOpen) { + setAplnRows([]); + setIsEditingLocked(false); + onClose(); + } + } + + function handleConfirm() { + const rowsError = validateAllRowsForSave(aplnRows, isEditingLocked); + if (rowsError) { + alert(rowsError); + return; + } + + const orderError = validateAtrzOrder(aplnRows); + if (orderError) { + alert(orderError); + return; + } + + const seqError = validateUniqueSeqNo(aplnRows); + if (seqError) { + alert(seqError); + return; + } + + const visibleRows = getVisibleRows(aplnRows); + onConfirm?.({ aplnRows: visibleRows }); + + setAplnRows([]); + setIsEditingLocked(false); + onClose(); + } + + return ( + + + + 결재선 선택 + + + + + + + + + + + ); +} + +export { ElaprDocPrgrsPickerDialog }; +export type { ElaprDocPrgrsPickerConfirmPayload }; diff --git a/apps/as/src/entities/elapr/ui/elapr-doc-prgrs-status.tsx b/apps/as/src/entities/elapr/ui/elapr-doc-prgrs-status.tsx index 4be4cf0c3..ea23484e4 100644 --- a/apps/as/src/entities/elapr/ui/elapr-doc-prgrs-status.tsx +++ b/apps/as/src/entities/elapr/ui/elapr-doc-prgrs-status.tsx @@ -1,6 +1,6 @@ "use client"; -import { Fragment } from "react"; +import { Fragment, useEffect, useMemo, useState } from "react"; import { ChevronRight } from "lucide-react"; @@ -8,7 +8,7 @@ import { dayjs, useUserStore } from "@/shared/lib"; import type { ElaprDocPrgrsClientResponseDto } from "@/shared/model"; import { SectionCollapsible } from "@/shared/ui"; import { Tooltip, TooltipContent, TooltipTrigger } from "@/shared/ui/tooltip"; -import { cn, Skeleton } from "@common/components"; +import { cn, Skeleton, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components"; import { useElaprDocPrgrsByDocNo } from "../api/queries"; import { getApproverStatus, sortByAtrzSeqNo } from "../lib/approval-utils"; @@ -67,10 +67,46 @@ function ElaprDocPrgrsStep({ item }: { item: ElaprDocPrgrsClientResponseDto }) { ); } +function ElaprDocPrgrsStepList({ steps }: { steps: ElaprDocPrgrsClientResponseDto[] }) { + if (steps.length === 0) { + return

결재선이 없습니다.

; + } + + return ( +
+ {steps.map((item, index) => ( + + {index > 0 && ( +
+ +
+ )} + +
+ ))} +
+ ); +} + function ElaprDocPrgrsStatus({ elaprDocNo }: ElaprDocPrgrsStatusProps) { const userInfo = useUserStore((state) => state.userInfo); const { data, isLoading } = useElaprDocPrgrsByDocNo(elaprDocNo); - const steps = sortByAtrzSeqNo(data ?? []); + const [activeCycl, setActiveCycl] = useState<"1" | "2">("1"); + + const { cycl1Steps, cycl2Steps, hasCycl2 } = useMemo(() => { + const rows = data ?? []; + const cycl1 = sortByAtrzSeqNo(rows.filter((item) => Number(item.elaprCycl ?? 1) !== 2)); + const cycl2 = sortByAtrzSeqNo(rows.filter((item) => Number(item.elaprCycl) === 2)); + return { + cycl1Steps: cycl1, + cycl2Steps: cycl2, + hasCycl2: cycl2.length > 0, + }; + }, [data]); + + useEffect(() => { + setActiveCycl(hasCycl2 ? "2" : "1"); + }, [hasCycl2]); if (userInfo?.dtlInstCd !== "ROLE_USER01") { return null; @@ -88,24 +124,40 @@ function ElaprDocPrgrsStatus({ elaprDocNo }: ElaprDocPrgrsStatusProps) { ); } - if (steps.length === 0) { + if (cycl1Steps.length === 0 && cycl2Steps.length === 0) { return null; } return ( -
- {steps.map((item, index) => ( - - {index > 0 && ( -
- {} -
- )} - -
- ))} -
+ {hasCycl2 ? ( + setActiveCycl(value as "1" | "2")} + className="p-2" + > + + + 재원협의 + + + 실무협의서 + + + +
+ +
+
+ +
+ +
+
+
+ ) : ( + + )}
); } diff --git a/apps/as/src/pages/fnrs-cnsltn/lib/button-config.ts b/apps/as/src/pages/fnrs-cnsltn/lib/button-config.ts index d0b906dae..92bf5b83e 100644 --- a/apps/as/src/pages/fnrs-cnsltn/lib/button-config.ts +++ b/apps/as/src/pages/fnrs-cnsltn/lib/button-config.ts @@ -38,10 +38,7 @@ const ROLE_STATUS_BUTTON_ACTIONS: Record )} {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.dsgntRvwr) && ( - )} @@ -615,7 +638,11 @@ function FloatingActionButtons({ )} {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.dmndSplmnt) && ( - )} @@ -643,6 +670,13 @@ function FloatingActionButtons({ onConfirm={handleElaprTmpltConfirm} /> + setActiveDialog(null)} + onConfirm={handleElaprDocPrgrsConfirm} + /> + Date: Wed, 16 Sep 2026 14:19:39 +0900 Subject: [PATCH 02/20] =?UTF-8?q?[as]=20feat:=20=EC=8B=A4=EB=AC=B4?= =?UTF-8?q?=ED=98=91=EC=9D=98=EC=84=9C=20=EA=B2=80=ED=86=A0=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81(RR,=20RK)=20=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../docs/pwrk-cnsltn/ref-frontend-entities.md | 2 + .../as/docs/pwrk-cnsltn/ref-screen-buttons.md | 16 +++-- .../elapr/ui/elapr-approval-dialog.tsx | 22 ++++-- .../pages/fnrs-cnsltn/lib/button-config.ts | 43 ++++++++--- .../fnrs-cnsltn/lib/review-step-utils.ts | 5 +- .../ui/components/floating-action-buttons.tsx | 71 +++++++++++-------- 6 files changed, 103 insertions(+), 56 deletions(-) diff --git a/apps/as/docs/pwrk-cnsltn/ref-frontend-entities.md b/apps/as/docs/pwrk-cnsltn/ref-frontend-entities.md index ddb0f5f3d..fdb817e08 100644 --- a/apps/as/docs/pwrk-cnsltn/ref-frontend-entities.md +++ b/apps/as/docs/pwrk-cnsltn/ref-frontend-entities.md @@ -346,3 +346,5 @@ To-Be: - 검토자지정은 **`ER`(1차)** 과 **`EV`(2차)** 에서. - `ER`: `elaprCycl: 1`, `docPrgrsSttsComCd: "AC"`, 서식 선택 다이얼로그 - `EV`: `elaprCycl: 2`, `docPrgrsSttsComCd: "RK"`, 1차 결재선 시드 다이얼로그(서식 없음) + +`RK` / ATRZ02 FAB: `findDocPrgrsByDocNo` 전체 조회 후 pending은 `elaprCycl === 2`만 사용. 검토완료 후 `ElaprApprovalDialog`에 `elaprCycl={2}`. 보완요청은 TE와 동일 `SplmntDmndDialog`. diff --git a/apps/as/docs/pwrk-cnsltn/ref-screen-buttons.md b/apps/as/docs/pwrk-cnsltn/ref-screen-buttons.md index 1c9d8565d..c0b7d2a08 100644 --- a/apps/as/docs/pwrk-cnsltn/ref-screen-buttons.md +++ b/apps/as/docs/pwrk-cnsltn/ref-screen-buttons.md @@ -70,7 +70,7 @@ API 컬럼은 [ref-endpoint.md](./ref-endpoint.md)와 동일. | 33 | 상세 | USER01 | 검토자 | `RK` | 검토완료 | `RK` | 다음 결재자 | `process` | | 34 | 상세 | USER01 | 승인자 | `RK` | 결재(승인) | `RK` | 다음 결재자 | `process` | | 35 | 상세 | USER01 | 최종승인자 | `RK` | 결재(회신) | `RR` | 환경청 | `process` 최종 | -| 36 | 상세 | USER03 | - | `RR` | 결과회신 | `EP` | 광역 | `updatePrgrsStts` | +| 36 | 상세 | USER03 | - | `RR` | 실무협의서 관리(조회), 검토결과 회신 | `EP` | 광역 | `tech-review` | | 37 | 작성/상세 | USER04 | - | `EP` | 결과회신 | `TA` | 기초 | `updatePrgrsStts` | | 38 | 상세 | USER05 | - | `TA` | 결과회신 | — | — | **API 없음. 조회** | @@ -121,7 +121,7 @@ ROLE_USER03 LE → 결과회신(자체종결), 기술검토 의뢰 TP → 재원협의 결과 회신 RA → 실무협의서 관리(조회), 조치결과 검토의뢰 - RR → 결과회신 + RR → 실무협의서 관리(조회), 검토결과 회신 (`tech-review` → `EP`) ``` ### 3-2. 공단 결재선 × 상태 @@ -141,14 +141,18 @@ TE / ATRZ03 승인자 → 결재(승인) TE / ATRZ99 최종 → 결재(회신) RK / ATRZ02 검토자 - → 실무협의서관리, 금액검증, 저장, 검토완료, 보완요청 -RK / ATRZ03 → 결재(승인) -RK / ATRZ99 → 결재(회신) + → (초안 완료) 실무협의서관리 + → (초안 완료 + 결재 대기 ATRZ_PRGRS_002, cycl2) 보완요청, 검토완료 + · 보완요청 UI: TE와 동일 SplmntDmndDialog +RK / ATRZ03 → (초안 완료) 실무협의서관리, (cycl2 pending) 결재(승인) +RK / ATRZ99 → (초안 완료) 실무협의서관리, (cycl2 pending) 결재(회신) + · 결재 UI: ElaprApprovalDialog (elaprCycl=2) 승인/반려 → PUT process ``` `FV`, `AC`, `AV`: 액션 빈 배열 + 진행 패널. -현행 `TE`에서 `hasPendingApprovalRequest === false`이면 버튼을 숨긴다. v3.0에서는 검토자 버튼(저장·웹기안기·보완)은 결재 대기와 무관하게 두고, **검토완료/결재**만 결재건 존재 여부에 묶는다. +`PENDING_APPROVAL_ACTIONS`: `dmndSplmnt`, `rvwCmptn`, `atrzAprv`, `atrzRply`만. +`pwrkCnsltnDocMng`는 결재 대기와 무관(초안 완료만). ATRZ02·ATRZ03·ATRZ99라도 pending 없으면 관리만 노출. --- diff --git a/apps/as/src/entities/elapr/ui/elapr-approval-dialog.tsx b/apps/as/src/entities/elapr/ui/elapr-approval-dialog.tsx index ad9abfa3e..0f7cfd056 100644 --- a/apps/as/src/entities/elapr/ui/elapr-approval-dialog.tsx +++ b/apps/as/src/entities/elapr/ui/elapr-approval-dialog.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState } from "react"; +import { useMemo, useState } from "react"; import { closestCenter, DndContext, type DragEndEvent } from "@dnd-kit/core"; import { SortableContext, verticalListSortingStrategy } from "@dnd-kit/sortable"; @@ -48,6 +48,7 @@ interface ElaprApprovalDialogProps { onOpenChange: (open: boolean) => void; elaprDocNo: string; currentUserUuid: string; + elaprCycl?: number; onSuccess: () => void; } @@ -58,6 +59,7 @@ function ElaprApprovalDialog({ onOpenChange, elaprDocNo, currentUserUuid, + elaprCycl, onSuccess, }: ElaprApprovalDialogProps) { const queryClient = useQueryClient(); @@ -67,9 +69,15 @@ function ElaprApprovalDialog({ const [pickerOpen, setPickerOpen] = useState(false); const [pickingRowKey, setPickingRowKey] = useState(null); - const { data: elaprDocPrgrsList, isLoading } = useElaprDocPrgrsByDocNo(open ? elaprDocNo : null); + const { data: elaprDocPrgrsList, isLoading } = useElaprDocPrgrsByDocNo(open ? elaprDocNo : null, { + elaprCycl, + }); + const cyclDocPrgrsList = useMemo(() => { + if (elaprCycl == null) return elaprDocPrgrsList; + return elaprDocPrgrsList?.filter((row) => Number(row.elaprCycl) === elaprCycl); + }, [elaprCycl, elaprDocPrgrsList]); - const elaprDmndId = elaprDocPrgrsList?.[0]?.elaprDmndId; + const elaprDmndId = cyclDocPrgrsList?.[0]?.elaprDmndId; const { rows, @@ -85,7 +93,7 @@ function ElaprApprovalDialog({ markDeleted, reorderRows, } = usePrgrsSttsRows({ - serverRows: elaprDocPrgrsList, + serverRows: cyclDocPrgrsList, elaprDmndId, }); @@ -93,14 +101,14 @@ function ElaprApprovalDialog({ const sensors = useDndSensors(); const currentUserPrgrs = findCurrentUserPendingApprovalRequest( - elaprDocPrgrsList, + cyclDocPrgrsList, currentUserUuid, ); const canApprove = Boolean(currentUserPrgrs?.elaprPrgrsId); const pickingRow = pickingRowKey ? rows.find((r) => r.rowKey === pickingRowKey) : undefined; const isBusy = isProcessing || savePrgrsSttsMutation.isPending; - const isPrgrsSttsUnsaved = hasUnsavedPrgrsSttsChanges(rows, elaprDocPrgrsList ?? []); + const isPrgrsSttsUnsaved = hasUnsavedPrgrsSttsChanges(rows, cyclDocPrgrsList ?? []); function handleDragEnd(event: DragEndEvent) { const { active, over } = event; @@ -164,7 +172,7 @@ function ElaprApprovalDialog({ return; } - const payload = buildPrgrsSttsSavePayload(rows, elaprDmndId, elaprDocPrgrsList ?? []); + const payload = buildPrgrsSttsSavePayload(rows, elaprDmndId, cyclDocPrgrsList ?? []); if (payload.length === 0) { alert("변경된 결재선이 없습니다."); return; diff --git a/apps/as/src/pages/fnrs-cnsltn/lib/button-config.ts b/apps/as/src/pages/fnrs-cnsltn/lib/button-config.ts index 92bf5b83e..cb705cffe 100644 --- a/apps/as/src/pages/fnrs-cnsltn/lib/button-config.ts +++ b/apps/as/src/pages/fnrs-cnsltn/lib/button-config.ts @@ -53,10 +53,14 @@ const ROLE_STATUS_BUTTON_ACTIONS: Record([ - ...ROLE_USER01_ATRZ_STATUS_ACTIONS.TE.ATRZ02, + FNRS_CNSLTN_VIEW_BUTTON_ACTION.dmndSplmnt, + FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwCmptn, FNRS_CNSLTN_VIEW_BUTTON_ACTION.atrzAprv, FNRS_CNSLTN_VIEW_BUTTON_ACTION.atrzRply, ]); @@ -129,15 +146,19 @@ function resolveRoleUser01AtrzButtonActions( const needsPendingApproval = PENDING_APPROVAL_ACTIONS.has(action); if (needsPendingApproval && options?.hasPendingApprovalRequest === false) return false; - if (prgrsSttsComCd === "TE" && options?.hasCompletedDraft != null) { - if ( - action === FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng || - action === FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwRsltInq - ) { - return options.hasCompletedDraft; + if (options?.hasCompletedDraft != null) { + if (prgrsSttsComCd === "TE" || prgrsSttsComCd === "RK") { + if (action === FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng) { + return options.hasCompletedDraft; + } } - if (action === FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocCrt) { - return !options.hasCompletedDraft; + if (prgrsSttsComCd === "TE") { + if (action === FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwRsltInq) { + return options.hasCompletedDraft; + } + if (action === FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocCrt) { + return !options.hasCompletedDraft; + } } } diff --git a/apps/as/src/pages/fnrs-cnsltn/lib/review-step-utils.ts b/apps/as/src/pages/fnrs-cnsltn/lib/review-step-utils.ts index bce365857..0ba84b926 100644 --- a/apps/as/src/pages/fnrs-cnsltn/lib/review-step-utils.ts +++ b/apps/as/src/pages/fnrs-cnsltn/lib/review-step-utils.ts @@ -32,7 +32,10 @@ export function getEditableReviewStep( dtlInstCd?: string, prgrsSttsComCd?: string, ): ReviewStepCode | undefined { - if (dtlInstCd === "ROLE_USER03" && (prgrsSttsComCd === "LE" || prgrsSttsComCd === "TP")) { + if ( + dtlInstCd === "ROLE_USER03" && + (prgrsSttsComCd === "LE" || prgrsSttsComCd === "TP" || prgrsSttsComCd === "RR") + ) { return "ENV"; } 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 83a38980d..187a72fa3 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 @@ -113,30 +113,37 @@ function FloatingActionButtons({ const isRegister = data.detDto?.rgtr === userInfo?.userUnqId; const needsAtrzResolve = needsRoleUser01AtrzResolve(dtlInstCd, prgrsSttsComCd); - const needsTeApprovalCheck = needsAtrzResolve && prgrsSttsComCd === "TE"; + const needsElaprPrgrsCheck = needsAtrzResolve && ["TE", "RK"].includes(prgrsSttsComCd); const needsPwrkDraftCheck = dtlInstCd === "ROLE_USER01" && ["TE", "RK"].includes(prgrsSttsComCd); const needsPwrkForRb = dtlInstCd === "ROLE_USER05" && prgrsSttsComCd === "RB"; const needsPwrkLookup = needsPwrkDraftCheck || needsPwrkForRb; + const { data: elaprDocPrgrsList = [], isLoading: isElaprDocPrgrsLoading } = - useElaprDocPrgrsByDocNo(needsTeApprovalCheck ? docNo : null); + useElaprDocPrgrsByDocNo(needsElaprPrgrsCheck ? docNo : null); + const { data: pwrkCnsltnData, isLoading: isPwrkCnsltnLoading } = usePwrkCnsltnMngByUpDocNo( docNo, needsPwrkLookup, ); + const hasCompletedDraft = Boolean(findCompletedPwrkDraft(pwrkCnsltnData)); const pwrkCnsltnDocNo = pwrkCnsltnData?.pwrkCnsltnDocNo; + const elaprPrgrsForPending = + prgrsSttsComCd === "RK" + ? elaprDocPrgrsList.filter((row) => Number(row.elaprCycl) === 2) + : elaprDocPrgrsList; const hasPendingApprovalRequest = hasCurrentUserPendingApprovalRequest( - elaprDocPrgrsList, + elaprPrgrsForPending, userInfo?.userUnqId, ); const actionButtons = useMemo(() => { if (needsAtrzResolve && isRvwLoginUserLoading) return []; - if (needsTeApprovalCheck && isElaprDocPrgrsLoading) return []; + if (needsElaprPrgrsCheck && isElaprDocPrgrsLoading) return []; if (needsPwrkDraftCheck && isPwrkCnsltnLoading) return []; return getButtonConfigs(dtlInstCd, prgrsSttsComCd, atrzSeComCdList, { - hasPendingApprovalRequest: needsTeApprovalCheck ? hasPendingApprovalRequest : undefined, + hasPendingApprovalRequest: needsElaprPrgrsCheck ? hasPendingApprovalRequest : undefined, hasCompletedDraft: needsPwrkDraftCheck ? hasCompletedDraft : undefined, }); }, [ @@ -148,7 +155,7 @@ function FloatingActionButtons({ isPwrkCnsltnLoading, isRvwLoginUserLoading, needsAtrzResolve, - needsTeApprovalCheck, + needsElaprPrgrsCheck, needsPwrkDraftCheck, prgrsSttsComCd, ]); @@ -336,11 +343,12 @@ function FloatingActionButtons({ return; } + const isResultReply = prgrsSttsComCd === "RR"; const payload = buildTechReviewReplyPayload( data, checklistFormState, "ENV", - "RM", + isResultReply ? "EP" : "RM", "CP", getReviewOpinionFormData(), opnrNm, @@ -349,7 +357,9 @@ function FloatingActionButtons({ await executeAction({ action: FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwRply, request: payload, - successMessage: "재원협의 결과 회신이 완료되었습니다.", + successMessage: isResultReply + ? "검토결과 회신이 완료되었습니다." + : "재원협의 결과 회신이 완료되었습니다.", }); techReviewOpinionRef?.current?.resetForm(); } @@ -432,15 +442,17 @@ function FloatingActionButtons({ } async function handleRvwCmptnClick() { - const { percent } = computeReviewStepChecklistProgress( - data.cklstResultList ?? [], - checklistFormState.results, - "KECO", - ); + if (prgrsSttsComCd === "TE") { + const { percent } = computeReviewStepChecklistProgress( + data.cklstResultList ?? [], + checklistFormState.results, + "KECO", + ); - if (percent !== 100) { - alert("모든 체크리스트 항목을 체크해야 검토완료가 가능합니다."); - return; + if (percent !== 100) { + alert("모든 체크리스트 항목을 체크해야 검토완료가 가능합니다."); + return; + } } const payload = { @@ -448,7 +460,7 @@ function FloatingActionButtons({ data, checklistFormState, "KECO", - "TE", + prgrsSttsComCd, "SV", getReviewOpinionFormData(), opnrNm, @@ -585,7 +597,7 @@ function FloatingActionButtons({ )} {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwRply) && ( )} {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rqstTechRvw) && ( @@ -698,6 +710,7 @@ function FloatingActionButtons({ onOpenChange={(open) => setActiveDialog(open ? "elaprApproval" : null)} elaprDocNo={data.detDto?.fnrsCnsltnDocNo ?? fnrsCnsltnDocNo} currentUserUuid={userInfo?.userUnqId ?? ""} + elaprCycl={prgrsSttsComCd === "RK" ? 2 : undefined} onSuccess={() => { queryClient.invalidateQueries({ queryKey: fnrsCnsltnKeys.detail(fnrsCnsltnDocNo), @@ -709,7 +722,13 @@ function FloatingActionButtons({ open={activeDialog === "pwrkCnsltnDocMng"} fnrsCnsltnDocNo={docNo} atrzSeComCdList={atrzSeComCdList} - canSave={prgrsSttsComCd === "RA" ? false : undefined} + canSave={ + prgrsSttsComCd === "RA" || + prgrsSttsComCd === "RR" || + (needsElaprPrgrsCheck && !hasPendingApprovalRequest) + ? false + : undefined + } onClose={() => setActiveDialog(null)} /> @@ -840,16 +859,6 @@ async function handleActnCmptn( } } -async function handleAtrzAprv(context: ActionHandlerContext): Promise { - // TODO: 결재 승인 처리 API 호출 - context.onSuccess?.(); -} - -async function handleAtrzRply(context: ActionHandlerContext): Promise { - // TODO: 결재 회신 처리 API 호출 - context.onSuccess?.(); -} - const buttonActionHandlers: Record = { strg: handleSaveApply, aply: handleSaveApply, @@ -869,8 +878,8 @@ const buttonActionHandlers: Record = rvwStrg: handleTechReview, rvwCmptn: handleTechReview, dmndSplmnt: handleDmndSplmnt, - atrzAprv: handleAtrzAprv, - atrzRply: handleAtrzRply, + atrzAprv: () => Promise.resolve(), + atrzRply: () => Promise.resolve(), actnCmptn: handleActnCmptn, rqstActnRvw: handleRequestActnReview, }; From 241222dcd12612a89cd276fa40ae8a9f68ffaac7 Mon Sep 17 00:00:00 2001 From: 100JM Date: Wed, 16 Sep 2026 14:52:38 +0900 Subject: [PATCH 03/20] =?UTF-8?q?[il]=20-=20=EC=97=B0=EA=B3=84=20db=20?= =?UTF-8?q?=ED=91=9C=EC=A4=80=ED=99=94=EB=A1=9C=20=EC=9D=B8=ED=95=9C=20?= =?UTF-8?q?=EC=86=8C=EC=8A=A4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/entities/link/model/link-interface.ts | 126 +++++++++--------- .../cs/src/pages/link/model/table-columns.tsx | 28 ++-- .../cs/src/pages/link/ui/LinkExpiredAlert.tsx | 10 +- apps/cs/src/pages/link/ui/link-form.tsx | 42 +++--- apps/cs/src/pages/link/ui/link-page.tsx | 4 +- apps/cs/src/pages/link/ui/modify-page.tsx | 10 +- apps/cs/src/pages/link/ui/regist-page.tsx | 22 +-- .../src/pages/linkLog/model/table-columns.tsx | 19 ++- .../cs/src/pages/linkLog/ui/link-log-page.tsx | 24 ++++ .../pages/linkParams/model/table-columns.tsx | 10 +- .../linkParams/model/vrbl-table-columns.tsx | 19 ++- .../linkParams/ui/link-params-dialog.tsx | 54 +++++--- .../pages/linkParams/ui/link-params-page.tsx | 16 +-- .../pages/linkStats/ui/link-stats-page.tsx | 6 +- .../pages/linkTable/ui/link-table-dialog.tsx | 26 ++-- .../pages/linkTable/ui/link-table-page.tsx | 44 +++--- 16 files changed, 257 insertions(+), 203 deletions(-) diff --git a/apps/cs/src/entities/link/model/link-interface.ts b/apps/cs/src/entities/link/model/link-interface.ts index 67cd75807..7640e3b8f 100644 --- a/apps/cs/src/entities/link/model/link-interface.ts +++ b/apps/cs/src/entities/link/model/link-interface.ts @@ -1,61 +1,62 @@ -import { z } from "zod"; +import { z } from "zod"; import type { PageableParams, PageableList } from "@/shared/model"; export interface Link { - link_sn: string; + intg_link_sn: string; link_nm: string; link_clsf_cd: string; - link_url: string; - link_srvr_ip: string; - link_db_cd: string; - link_key: string; - link_id: string; - link_pswd: string; - link_cycle_stng: string; - srvc_usg: string; - last_link_rslt_cd: string; + link_url_addr: string; + link_srvr_ip_addr: string; + link_db_nm: string; + link_api_no: string; + link_cntn_nm: string; + link_cntn_tkn_no: string; + link_cycle_stng_nm: string; + srvc_usg_nm: string; + last_link_rslt_nm: string; last_link_excn_dt: string; next_link_excn_dt: string; - last_link_err_cd: string; + last_link_err_nm: string; mdfcn_dt: string; - mdfr_id_id: string; - link_cycle_mi: string; - link_key_expry_ymd: string; + mdfr_uuid: string; + link_cycle_no: string; + link_expry_ymd: string; } export interface LinkLog { rownum: number; - link_sn: string; + intg_link_sn: string; link_nm: string; - link_rslt_cd: string; + link_rslt_nm: string; err_cn: string; - link_err_cd: string; + link_err_nm: string; log_crt_dt: string; + link_exec_step: string; } export interface LinkInfo extends LinkFormData { - link_sn: string; + intg_link_sn: string; link_nm: string; link_clsf_cd: string; - link_url: string; - link_srvr_ip: string; - link_db_cd: string; - link_key: string; - link_id: string; - link_pswd: string; - srvc_usg: string; - last_link_rslt_cd: string; + link_url_addr: string; + link_srvr_ip_addr: string; + link_db_nm: string; + link_api_no: string; + link_cntn_nm: string; + link_cntn_tkn_no: string; + srvc_usg_nm: string; + last_link_rslt_nm: string; last_link_excn_dt: string; next_link_excn_dt: string; - last_link_err_cd: string; + last_link_err_nm: string; mdfcn_dt: string; - mdfr_id: string; - link_cycle_mi: number; - link_key_expry_ymd: string; + mdfr_uuid: string; + link_cycle_no: number; + link_expry_ymd: string; } export interface LinkStats { - link_sn: string; + intg_link_sn: string; link_nm: string; count: number; } @@ -63,16 +64,16 @@ export interface LinkStats { export interface LinkVrbl { link_vrbl_sn: string; link_vrbl_nm: string; - link_vrbl_vl: string; - link_vrbl_cd: string; + link_vrbl_vl_cn: string; + link_vrbl_cd_nm: string; link_vrbl_expln: string; mdfcn_dt: string; - mdfr_id: string; + mdfr_uuid: string; } export interface LinkTable { link_nm: string; - link_sn: string; + intg_link_sn: string; tbl_sn: string; sou_tbl_nm: string; sou_tbl_korn_nm: string; @@ -87,16 +88,16 @@ export interface LinkTableColumns { col_sn: string; sou_col_nm: string; sou_col_korn_nm: string; - sou_col_data_frm: string; + sou_col_frm_nm: string; sou_col_sz: number; trsf_col_nm: string; trsf_col_korn_nm: string; - trsf_col_data_frm: string; + trsf_col_frm_nm: string; trsf_col_sz: number pk_yn: string; col_seq: number; mdfcn_dt: string; - mdfr_id: string; + mdfr_uuid: string; } export const linkFormSchema = z.object({ @@ -106,48 +107,48 @@ export const linkFormSchema = z.object({ }, { message: "연계 분류를 선택해주세요" }), - link_sn: z.string().max(50).nullable().optional(), + intg_link_sn: z.string().max(50).nullable().optional(), link_nm: z.string().max(40, { message: '연계명은 40자 이하로 입력해 주세요.' }).nonempty({ message: '연계명은 필수입니다.' }), - link_url: z.string().max(1000, { message: '연계 URL은 1000자 이하로 입력해 주세요.' }).nonempty({ message: '연계 URL은 필수입니다.' }), - link_srvr_ip: z.string().max(20).nullable().optional(), - link_db_cd: z.string().max(10).nullable().optional(), - link_key: z.string().max(100, { message: '연계 KEY는 100자 이하로 입력해 주세요.' }).nonempty({ message: '연계 KEY는 필수입니다.' }), - link_id: z.string().max(20).nullable().optional(), - link_pswd: z.string().max(128).nullable().optional(), - srvc_usg: z.string().max(40).nullable().optional(), - last_link_rslt_cd: z.string().max(4).nullable().optional(), + link_url_addr: z.string().max(1000, { message: '연계 URL은 1000자 이하로 입력해 주세요.' }).nonempty({ message: '연계 URL은 필수입니다.' }), + link_srvr_ip_addr: z.string().max(20).nullable().optional(), + link_db_nm: z.string().max(10).nullable().optional(), + link_api_no: z.string().max(100, { message: '연계 KEY는 100자 이하로 입력해 주세요.' }).nonempty({ message: '연계 KEY는 필수입니다.' }), + link_cntn_nm: z.string().max(20).nullable().optional(), + link_cntn_tkn_no: z.string().max(128).nullable().optional(), + srvc_usg_nm: z.string().max(40).nullable().optional(), + last_link_rslt_nm: z.string().max(4).nullable().optional(), last_link_excn_dt: z.string().max(40).nullable().optional(), next_link_excn_dt: z.string().max(40).nullable().optional(), - last_link_err_cd: z.string().max(50, { message: '마지막 연계 오류 코드는 50자 이하입니다.' }).nullable().optional(), + last_link_err_nm: z.string().max(50, { message: '마지막 연계 오류 코드는 50자 이하입니다.' }).nullable().optional(), mdfcn_dt: z.string().nullable().optional(), - mdfr_id: z.string().nullable().optional(), - link_cycle_mi: z.coerce.number().nullable().optional().refine((val) => { + mdfr_uuid: z.string().nullable().optional(), + link_cycle_no: z.coerce.number().nullable().optional().refine((val) => { if (val == null) return true; return val >= 5; }, { message: "연계 주기는 5분 이상이어야 합니다." }), - link_key_expry_ymd: z.string().nullable().optional(), + link_expry_ymd: z.string().nullable().optional(), }); export const linkVrblFormSchema = z.object({ - link_sn: z.string().max(50).nullable().optional(), + intg_link_sn: z.string().max(50).nullable().optional(), link_vrbl_sn: z.string().max(50).nullable().optional(), link_vrbl_nm: z.string().max(40, { message: '변수명은 40자 이하로 입력해 주세요.' }).nonempty({ message: '변수명은 필수입니다.' }), link_vrbl_expln: z.string().max(4000, { message: '설명은 400자 이하로 입력해 주세요.' }).nullable().optional(), - link_vrbl_cd: z.string().max(10, { message: '변수코드는 10자 이하로 입력해 주세요.' }).nullable().optional(), - link_vrbl_vl: z.string().max(1000, { message: '변수값은 1000자 이하로 입력해 주세요.' }).nonempty({ message: '변수값은 필수입니다.' }), + link_vrbl_cd_nm: z.string().max(10, { message: '변수코드는 10자 이하로 입력해 주세요.' }).nullable().optional(), + link_vrbl_vl_cn: z.string().max(1000, { message: '변수값은 1000자 이하로 입력해 주세요.' }).nonempty({ message: '변수값은 필수입니다.' }), mdfcn_dt: z.string().nullable().optional(), - mdfr_id: z.string().nullable().optional(), + mdfr_uuid: z.string().nullable().optional(), }); export const LinkTableColumnsSchema = z.object({ - link_sn: z.string().max(50).nullable().optional(), + intg_link_sn: z.string().max(50).nullable().optional(), tbl_sn: z.string().max(50).nullable().optional(), col_sn: z.string().max(50).nullable().optional(), sou_col_nm: z.string().max(40, { message: '40자 이하로 입력해 주세요.' }).nullable().optional(), sou_col_korn_nm: z.string().max(40, { message: '40자 이하로 입력해 주세요.' }).nullable().optional(), - sou_col_data_frm: z.string().max(40, { message: '40자 이하로 입력해 주세요.' }).nullable().optional(), + sou_col_frm_nm: z.string().max(40, { message: '40자 이하로 입력해 주세요.' }).nullable().optional(), sou_col_sz: z.coerce.number().nullable().optional().refine((val) => { if (val == null) return true; return val.toString().replace('.', '').length <= 14; @@ -157,7 +158,7 @@ export const LinkTableColumnsSchema = z.object({ pk_yn: z.string().max(1).nonempty(), trsf_col_nm: z.string().max(40, { message: '40자 이하로 입력해 주세요.' }).nonempty({ message: '변환컬럼명은 필수입니다.' }), trsf_col_korn_nm: z.string().max(40, { message: '40자 이하로 입력해 주세요.' }).nonempty({ message: '변환컬럼 한글명은 필수입니다.' }), - trsf_col_data_frm: z.string().max(40, { message: '40자 이하로 입력해 주세요.' }).nonempty({ message: '변환컬럼 데이터 형식은 필수입니다.' }), + trsf_col_frm_nm: z.string().max(40, { message: '40자 이하로 입력해 주세요.' }).nonempty({ message: '변환컬럼 데이터 형식은 필수입니다.' }), trsf_col_sz: z.coerce.number().nullable().optional().refine((val) => { if (val == null) return true; return val.toString().replace('.', '').length <= 14; @@ -166,11 +167,11 @@ export const LinkTableColumnsSchema = z.object({ }), col_seq: z.coerce.number().nullable().optional(), mdfcn_dt: z.string().nullable().optional(), - mdfr_id: z.string().nullable().optional(), + mdfr_uuid: z.string().nullable().optional(), }); export const LinkTableSchema = z.object({ - link_sn: z.string().max(50).nullable().optional(), + intg_link_sn: z.string().max(50).nullable().optional(), tbl_sn: z.string().max(50).nullable().optional(), link_nm: z.string().max(50).nullable().optional(), sou_tbl_nm: z.string().max(40, { message: '40자 이하로 입력해 주세요.' }).nullable().optional(), @@ -180,7 +181,7 @@ export const LinkTableSchema = z.object({ trsf_tbl_korn_nm: z.string().max(40, { message: '40자 이하로 입력해 주세요.' }).nonempty({ message: '변환테이블 한글명은 필수입니다.' }), trsf_tbl_expln: z.string().max(2000, { message: '설명은 2000자 이하로 입력해 주세요.' }).nullable().optional(), mdfcn_dt: z.string().nullable().optional(), - mdfr_id: z.string().nullable().optional(), + mdfr_uuid: z.string().nullable().optional(), }); interface LinkStatsListObject { @@ -195,6 +196,7 @@ export interface LinkSearchParam extends PageableParams { endDate?: string; isSucc?: string; linkClfsCd?: string; + linkExecStep?: string; } export type LinkFormData = z.infer; diff --git a/apps/cs/src/pages/link/model/table-columns.tsx b/apps/cs/src/pages/link/model/table-columns.tsx index 800801277..829743849 100644 --- a/apps/cs/src/pages/link/model/table-columns.tsx +++ b/apps/cs/src/pages/link/model/table-columns.tsx @@ -1,4 +1,4 @@ -import dayjs from "dayjs"; +import dayjs from "dayjs"; import { createColumnHelper } from "@tanstack/react-table"; import { type Link } from "@/entities/link"; import QuickStartButton from "../ui/QuickStartButton"; @@ -35,39 +35,39 @@ const columns = [ id: 'no', header: 'NO', }), - columnHelper.accessor('link_sn', { - id: 'link_sn', + columnHelper.accessor('intg_link_sn', { + id: 'intg_link_sn', header: '연계일련번호', }), columnHelper.accessor('link_nm', { id: 'link_nm', header: '연계 명', }), - columnHelper.accessor('link_url', { - id: 'link_url', + columnHelper.accessor('link_url_addr', { + id: 'link_url_addr', header: '연계 URL', cell: (info) => (info.getValue() ? info.getValue() : '-'), }), - columnHelper.accessor('link_srvr_ip', { - id: 'link_srvr_ip', + columnHelper.accessor('link_srvr_ip_addr', { + id: 'link_srvr_ip_addr', header: '연계서버 IP', cell: (info) => (info.getValue() ? info.getValue() : '-'), }), - columnHelper.accessor('link_cycle_mi', { - id: 'link_cycle_mi', + columnHelper.accessor('link_cycle_no', { + id: 'link_cycle_no', header: '연계 주기', cell: (info) => convertMinutesToPeriod(Number(info.getValue())), }), - columnHelper.accessor('srvc_usg', { - id: 'srvc_usg', + columnHelper.accessor('srvc_usg_nm', { + id: 'srvc_usg_nm', header: '서비스용도', cell: (info) => (info.getValue() ? info.getValue() : '-'), }), columnHelper.display({ - id: 'last_link_rslt_cd', + id: 'last_link_rslt_nm', header: '연계상태', cell: (info) => { - const resultCd = info.row.original.last_link_rslt_cd; + const resultCd = info.row.original.last_link_rslt_nm; return {resultCd === 'SUCC' ? '성공' : (resultCd === 'FAIL' ? '실패' : (resultCd === 'RUNN' ? '진행중' : '대기'))} }, }), @@ -80,7 +80,7 @@ const columns = [ id: 'quick_start_btn', header: '즉시 실행', cell: (info) => { - return + return } }) ]; diff --git a/apps/cs/src/pages/link/ui/LinkExpiredAlert.tsx b/apps/cs/src/pages/link/ui/LinkExpiredAlert.tsx index 92628a755..ab5091389 100644 --- a/apps/cs/src/pages/link/ui/LinkExpiredAlert.tsx +++ b/apps/cs/src/pages/link/ui/LinkExpiredAlert.tsx @@ -1,4 +1,4 @@ -import type { Link, LinkList } from "@/entities/link/model/link-interface"; +import type { Link, LinkList } from "@/entities/link/model/link-interface"; import { Button, DropdownMenu, @@ -18,11 +18,11 @@ const LinkExpiredAlert = ({ linkList }: { linkList: UseQueryResult }) useEffect(() => { if (linkList?.data?.content) { const expriedLinks = linkList.data.content.filter((l) => { - if (l.link_key_expry_ymd === 'none' || !l.link_key_expry_ymd) { + if (l.link_expry_ymd === 'none' || !l.link_expry_ymd) { return false; } - const expryDate = dayjs(l.link_key_expry_ymd, 'YYMMDD'); + const expryDate = dayjs(l.link_expry_ymd, 'YYMMDD'); const today = dayjs(); const daysDiff = expryDate.diff(today, 'day'); @@ -56,11 +56,11 @@ const LinkExpiredAlert = ({ linkList }: { linkList: UseQueryResult }) {expriedLinkList.length > 0 ? {expriedLinkList.map((l) => { - const expryDate = dayjs(l.link_key_expry_ymd, 'YYMMDD'); + const expryDate = dayjs(l.link_expry_ymd, 'YYMMDD'); const today = dayjs(); const daysDiff = expryDate.diff(today, 'day'); - return router.push(`link/register/${l.link_sn}`)}> + return router.push(`link/register/${l.intg_link_sn}`)}>
{daysDiff > 0 ?

{l.link_nm} API KEY 만료 {daysDiff}일전

diff --git a/apps/cs/src/pages/link/ui/link-form.tsx b/apps/cs/src/pages/link/ui/link-form.tsx index 51d8c9f18..6969c6165 100644 --- a/apps/cs/src/pages/link/ui/link-form.tsx +++ b/apps/cs/src/pages/link/ui/link-form.tsx @@ -1,4 +1,4 @@ -import { +import { Button, Input, Table, @@ -55,7 +55,7 @@ const LinkForm = ({ form, linkSn, updateLinkInfo, handleInsertLink, deleteLink, const newData = { ...data, - link_key_expry_ymd: isNoExprie ? 'none' :dayjs(expryDate).format('YYYYMMDD'), + link_expry_ymd: isNoExprie ? 'none' :dayjs(expryDate).format('YYYYMMDD'), }; await handleConfirm(async () => { @@ -133,7 +133,7 @@ const LinkForm = ({ form, linkSn, updateLinkInfo, handleInsertLink, deleteLink, ( @@ -222,7 +222,7 @@ const LinkForm = ({ form, linkSn, updateLinkInfo, handleInsertLink, deleteLink, ( @@ -233,9 +233,9 @@ const LinkForm = ({ form, linkSn, updateLinkInfo, handleInsertLink, deleteLink, autoComplete="off" /> - {form.formState.errors.link_url && ( + {form.formState.errors.link_url_addr && (

- {form.formState.errors.link_url.message} + {form.formState.errors.link_url_addr.message}

)}
@@ -250,7 +250,7 @@ const LinkForm = ({ form, linkSn, updateLinkInfo, handleInsertLink, deleteLink, ( @@ -277,7 +277,7 @@ const LinkForm = ({ form, linkSn, updateLinkInfo, handleInsertLink, deleteLink, ( @@ -288,9 +288,9 @@ const LinkForm = ({ form, linkSn, updateLinkInfo, handleInsertLink, deleteLink, autoComplete="off" /> - {form.formState.errors.link_key && ( + {form.formState.errors.link_api_no && (

- {form.formState.errors.link_key.message} + {form.formState.errors.link_api_no.message}

)}
@@ -303,7 +303,7 @@ const LinkForm = ({ form, linkSn, updateLinkInfo, handleInsertLink, deleteLink, ( @@ -333,9 +333,9 @@ const LinkForm = ({ form, linkSn, updateLinkInfo, handleInsertLink, deleteLink,
- {form.formState.errors.link_key_expry_ymd && ( + {form.formState.errors.link_expry_ymd && (

- {form.formState.errors.link_key_expry_ymd.message} + {form.formState.errors.link_expry_ymd.message}

)} @@ -348,7 +348,7 @@ const LinkForm = ({ form, linkSn, updateLinkInfo, handleInsertLink, deleteLink, ( @@ -369,7 +369,7 @@ const LinkForm = ({ form, linkSn, updateLinkInfo, handleInsertLink, deleteLink, ( @@ -391,7 +391,7 @@ const LinkForm = ({ form, linkSn, updateLinkInfo, handleInsertLink, deleteLink, ( @@ -412,7 +412,7 @@ const LinkForm = ({ form, linkSn, updateLinkInfo, handleInsertLink, deleteLink, { const timeParts = convertMinutesToPeriod(Number(field.value)); return ( @@ -510,9 +510,9 @@ const LinkForm = ({ form, linkSn, updateLinkInfo, handleInsertLink, deleteLink, - {form.formState.errors.link_cycle_mi && ( + {form.formState.errors.link_cycle_no && (

- {form.formState.errors.link_cycle_mi.message} + {form.formState.errors.link_cycle_no.message}

)}
@@ -528,7 +528,7 @@ const LinkForm = ({ form, linkSn, updateLinkInfo, handleInsertLink, deleteLink, { return ( @@ -596,7 +596,7 @@ const LinkForm = ({ form, linkSn, updateLinkInfo, handleInsertLink, deleteLink, ( diff --git a/apps/cs/src/pages/link/ui/link-page.tsx b/apps/cs/src/pages/link/ui/link-page.tsx index a59b9e751..ac13cd7d2 100644 --- a/apps/cs/src/pages/link/ui/link-page.tsx +++ b/apps/cs/src/pages/link/ui/link-page.tsx @@ -1,4 +1,4 @@ -"use client"; +"use client"; import "@common/assets/styles/grid.css"; @@ -78,7 +78,7 @@ function LinkPage() { `${process.env.NEXT_PUBLIC_LINK_BACKEND_API_HOST}/getLinkInfo`, ], }); - router.push(`link/register/${link.link_sn}`); + router.push(`link/register/${link.intg_link_sn}`); }; const handleClickRegist = () => { diff --git a/apps/cs/src/pages/link/ui/modify-page.tsx b/apps/cs/src/pages/link/ui/modify-page.tsx index 88a83f47b..97dd513e4 100644 --- a/apps/cs/src/pages/link/ui/modify-page.tsx +++ b/apps/cs/src/pages/link/ui/modify-page.tsx @@ -1,4 +1,4 @@ -"use client"; +"use client"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { LinkApi, linkFormSchema, type LinkFormData } from "@/entities/link"; @@ -37,7 +37,7 @@ function ModifyLinkPage({ linkSn }: { linkSn: string }) { mutationFn: (data: LinkFormData) => LinkApi.updateLinkInfo({ ...data, link_clsf_cd: data.link_clsf_cd !== 'none' ? data.link_clsf_cd : null, - mdfr_id: userUniqId + mdfr_uuid: userUniqId }), onSuccess: () => { alert('수정되었습니다.'); @@ -75,17 +75,17 @@ function ModifyLinkPage({ linkSn }: { linkSn: string }) { if (linkInfo) { let newData = { ...linkInfo }; - if (linkInfo.mdfr_id) { + if (linkInfo.mdfr_uuid) { const userName = await fetchUserInfo(); newData = { ...linkInfo, - mdfr_id: userName, + mdfr_uuid: userName, }; } form.reset(newData); - setInitialIsNoExprie(newData.link_key_expry_ymd === 'none'); + setInitialIsNoExprie(newData.link_expry_ymd === 'none'); } }; diff --git a/apps/cs/src/pages/link/ui/regist-page.tsx b/apps/cs/src/pages/link/ui/regist-page.tsx index 76912ab9f..e5635c8bd 100644 --- a/apps/cs/src/pages/link/ui/regist-page.tsx +++ b/apps/cs/src/pages/link/ui/regist-page.tsx @@ -1,4 +1,4 @@ -"use client"; +"use client"; import { LinkApi, type LinkFormData, linkFormSchema } from "@/entities/link"; import LinkForm from "./link-form"; @@ -20,14 +20,14 @@ function RegistLinkPage() { resolver: zodResolver(linkFormSchema), defaultValues: { link_nm: '', - link_url: '', - link_srvr_ip: '', - link_db_cd: '', - link_key: '', - link_id: '', - link_pswd: '', - srvc_usg: '', - link_cycle_mi: 5, + link_url_addr: '', + link_srvr_ip_addr: '', + link_db_nm: '', + link_api_no: '', + link_cntn_nm: '', + link_cntn_tkn_no: '', + srvc_usg_nm: '', + link_cycle_no: 5, link_clsf_cd: 'none', }, }); @@ -44,8 +44,8 @@ function RegistLinkPage() { const insertData = { ...data, link_clsf_cd: data.link_clsf_cd !== 'none' ? data.link_clsf_cd : null, - next_link_excn_dt: dayjs().add(Number(data.link_cycle_mi), 'minute').format('YYYY-MM-DD HH:mm:ss'), - mdfr_id: userUniqId, + next_link_excn_dt: dayjs().add(Number(data.link_cycle_no), 'minute').format('YYYY-MM-DD HH:mm:ss'), + mdfr_uuid: userUniqId, }; insertLinkInfo(insertData); diff --git a/apps/cs/src/pages/linkLog/model/table-columns.tsx b/apps/cs/src/pages/linkLog/model/table-columns.tsx index 30e7fa702..b5b2c7ff3 100644 --- a/apps/cs/src/pages/linkLog/model/table-columns.tsx +++ b/apps/cs/src/pages/linkLog/model/table-columns.tsx @@ -1,4 +1,4 @@ -import dayjs from "dayjs"; +import dayjs from "dayjs"; import { createColumnHelper } from "@tanstack/react-table"; import { type LinkLog } from "@/entities/link"; @@ -9,24 +9,29 @@ const columns = [ id: 'rownum', header: 'NO', }), - columnHelper.accessor('link_sn', { - id: 'link_sn', + columnHelper.accessor('intg_link_sn', { + id: 'intg_link_sn', header: '연계일련번호', }), columnHelper.accessor('link_nm', { id: 'link_nm', header: '연계 명', }), + columnHelper.accessor('link_exec_step', { + id: 'link_exec_step', + header: '연계실행단계', + cell: (info) => (info.getValue() ? info.getValue() : '-'), + }), columnHelper.display({ - id: 'link_rslt_cd', + id: 'link_rslt_nm', header: '연계실행결과', cell: (info) => { - const isSucc = info.row.original.link_rslt_cd.trim() === 'SUCC'; + const isSucc = info.row.original.link_rslt_nm.trim() === 'SUCC'; return {isSucc ? '성공' : '실패'} }, }), - columnHelper.accessor('link_err_cd', { - id: 'link_err_cd', + columnHelper.accessor('link_err_nm', { + id: 'link_err_nm', header: '연계오류코드', cell: (info) => (info.getValue() ? info.getValue() : '-'), }), diff --git a/apps/cs/src/pages/linkLog/ui/link-log-page.tsx b/apps/cs/src/pages/linkLog/ui/link-log-page.tsx index 5a0637b72..9dcd72341 100644 --- a/apps/cs/src/pages/linkLog/ui/link-log-page.tsx +++ b/apps/cs/src/pages/linkLog/ui/link-log-page.tsx @@ -33,6 +33,7 @@ function LinkLogPage() { const [linkSn, setLinkSn] = useState(""); const [linkNm, setLinkNm] = useState(""); + const [linkExecStep, setLinkExecStep] = useState("ALL"); const [isSucc, setIsSucc] = useState("ALL"); const [startDate, setStartDate] = useState( dayjs().subtract(7, "day").format("YYYY-MM-DD"), @@ -42,6 +43,7 @@ function LinkLogPage() { const [linkSearchParam, setLinkSearchParam] = useState({ linkSn: "", linkNm: "", + linkExecStep: "", isSucc: "", startDate: "", endDate: "", @@ -65,6 +67,7 @@ function LinkLogPage() { ...linkSearchParam, page: pagination.pageIndex, size: pagination.pageSize, + linkExecStep, isSucc, startDate, endDate, @@ -91,6 +94,7 @@ function LinkLogPage() { }); const handleResetSearchParam = () => { + setLinkExecStep("ALL"); setIsSucc("ALL"); setLinkNm(""); setLinkSn(""); @@ -100,6 +104,7 @@ function LinkLogPage() { ...linkSearchParam, linkSn: "", linkNm: "", + linkExecStep: "ALL", isSucc: "ALL", startDate: dayjs().subtract(7, "day").format("YYYY-MM-DD"), endDate: dayjs().format("YYYY-MM-DD"), @@ -122,6 +127,7 @@ function LinkLogPage() { ...linkSearchParam, linkSn, linkNm, + linkExecStep, isSucc, startDate, endDate, @@ -157,6 +163,24 @@ function LinkLogPage() { onChange={(e) => setLinkNm(e.target.value)} autoComplete="off" /> + + diff --git a/apps/cs/src/pages/linkParams/model/table-columns.tsx b/apps/cs/src/pages/linkParams/model/table-columns.tsx index a71a74e9d..868019e31 100644 --- a/apps/cs/src/pages/linkParams/model/table-columns.tsx +++ b/apps/cs/src/pages/linkParams/model/table-columns.tsx @@ -1,4 +1,4 @@ -import { createColumnHelper } from "@tanstack/react-table"; +import { createColumnHelper } from "@tanstack/react-table"; import { type Link } from "@/entities/link"; const columnHelper = createColumnHelper(); @@ -8,16 +8,16 @@ const columns = [ id: 'no', header: 'NO', }), - columnHelper.accessor('link_sn', { - id: 'link_sn', + columnHelper.accessor('intg_link_sn', { + id: 'intg_link_sn', header: '연계 일련번호', }), columnHelper.accessor('link_nm', { id: 'link_nm', header: '연계 명', }), - columnHelper.accessor('srvc_usg', { - id: 'srvc_usg', + columnHelper.accessor('srvc_usg_nm', { + id: 'srvc_usg_nm', header: '서비스용도', cell: (info) => (info.getValue() ? info.getValue() : '-'), }), diff --git a/apps/cs/src/pages/linkParams/model/vrbl-table-columns.tsx b/apps/cs/src/pages/linkParams/model/vrbl-table-columns.tsx index 26ccc7303..c9026097d 100644 --- a/apps/cs/src/pages/linkParams/model/vrbl-table-columns.tsx +++ b/apps/cs/src/pages/linkParams/model/vrbl-table-columns.tsx @@ -1,4 +1,4 @@ -import { createColumnHelper } from "@tanstack/react-table"; +import { createColumnHelper } from "@tanstack/react-table"; import { type LinkVrbl } from "@/entities/link"; import { Checkbox } from "@common/components"; @@ -70,15 +70,22 @@ function vrblColumns({ id: "link_vrbl_nm", header: "변수 명", }), - columnHelper.accessor("link_vrbl_cd", { - id: "link_vrbl_cd", + columnHelper.accessor("link_vrbl_cd_nm", { + id: "link_vrbl_cd_nm", header: "변수코드", cell: (info) => (info.getValue() ? info.getValue() : '-'), }), - columnHelper.accessor("link_vrbl_vl", { - id: "link_vrbl_vl", + columnHelper.accessor("link_vrbl_vl_cn", { + id: "link_vrbl_vl_cn", header: "변수 값", - cell: (info) => (info.getValue() === 'now' ? '요청일자' : info.getValue() === 'nowMonth' ? '요청월' : info.getValue()), + cell: (info) => { + const value = info.getValue(); + if (value === 'now') return '요청일자'; + if (value === 'nowMonth') return '요청월'; + if (value === 'nowHour') return '요청일자(시간포함)'; + if (value === 'nowHourMin') return '요청일자(시분포함)'; + return value; + }, }), columnHelper.accessor("link_vrbl_expln", { id: "link_vrbl_expln", diff --git a/apps/cs/src/pages/linkParams/ui/link-params-dialog.tsx b/apps/cs/src/pages/linkParams/ui/link-params-dialog.tsx index 9a3e2b87e..86675aede 100644 --- a/apps/cs/src/pages/linkParams/ui/link-params-dialog.tsx +++ b/apps/cs/src/pages/linkParams/ui/link-params-dialog.tsx @@ -1,4 +1,4 @@ -'use client'; +'use client'; import { Dialog, @@ -71,21 +71,29 @@ function LinkParamsDialog({ selectedLink, form, insertLinkVrbl, dialogOpen, onOp if (await confirm(confirmMsg)) { if (isModifyMode) { - updateLinkVrbl(isToday ? { ...cleanData, link_vrbl_vl: checkNowMonth } : cleanData); + updateLinkVrbl(isToday ? { ...cleanData, link_vrbl_vl_cn: checkNowMonth } : cleanData); } else { - insertLinkVrbl(isToday ? { ...cleanData, link_vrbl_vl: checkNowMonth } : cleanData); + insertLinkVrbl(isToday ? { ...cleanData, link_vrbl_vl_cn: checkNowMonth } : cleanData); } } }); }; + const getTodayValueLabel = (value: string) => { + if (value === 'now') return '요청일자'; + if (value === 'nowMonth') return '요청월'; + if (value === 'nowHour') return '요청일자(시간포함)'; + if (value === 'nowHourMin') return '요청일자(시분포함)'; + return value; + }; + const handleCheckTodayValue = (check: boolean | string) => { if (check) { setIsToday(true); - form.setValue('link_vrbl_vl', (checkNowMonth === 'now' ? '요청일자' : '요청월')); + form.setValue('link_vrbl_vl_cn', getTodayValueLabel(checkNowMonth)); } else { setIsToday(false); - form.setValue('link_vrbl_vl', ''); + form.setValue('link_vrbl_vl_cn', ''); } }; @@ -96,14 +104,14 @@ function LinkParamsDialog({ selectedLink, form, insertLinkVrbl, dialogOpen, onOp form.reset({ link_vrbl_nm: '', link_vrbl_expln: '', - link_vrbl_cd: '', - link_vrbl_vl: '', + link_vrbl_cd_nm: '', + link_vrbl_vl_cn: '', }); } - if (isModifyMode && (form.getValues('link_vrbl_vl') === 'now' || form.getValues('link_vrbl_vl') === 'nowMonth')) { + if (isModifyMode && ['now', 'nowMonth', 'nowHour', 'nowHourMin'].includes(form.getValues('link_vrbl_vl_cn') ?? '')) { setIsToday(true); - setCheckNowMonth(form.getValues('link_vrbl_vl')); + setCheckNowMonth(form.getValues('link_vrbl_vl_cn')); } }, [dialogOpen]); @@ -118,7 +126,7 @@ function LinkParamsDialog({ selectedLink, form, insertLinkVrbl, dialogOpen, onOp - + {selectedLink.linkNm} ({selectedLink.linkSn}) @@ -213,7 +221,7 @@ function LinkParamsDialog({ selectedLink, form, insertLinkVrbl, dialogOpen, onOp ( @@ -224,9 +232,9 @@ function LinkParamsDialog({ selectedLink, form, insertLinkVrbl, dialogOpen, onOp autoComplete="off" /> - {form.formState.errors.link_vrbl_cd && ( + {form.formState.errors.link_vrbl_cd_nm && (

- {form.formState.errors.link_vrbl_cd.message} + {form.formState.errors.link_vrbl_cd_nm.message}

)}
@@ -239,7 +247,7 @@ function LinkParamsDialog({ selectedLink, form, insertLinkVrbl, dialogOpen, onOp (
@@ -252,7 +260,7 @@ function LinkParamsDialog({ selectedLink, form, insertLinkVrbl, dialogOpen, onOp name="checkNowMonth" onValueChange={(value) => { setCheckNowMonth(value); - form.setValue('link_vrbl_vl', (value === 'now' ? '요청일자' : '요청월')); + form.setValue('link_vrbl_vl_cn', getTodayValueLabel(value)); }} >
@@ -263,21 +271,29 @@ function LinkParamsDialog({ selectedLink, form, insertLinkVrbl, dialogOpen, onOp
+
+ + +
+
+ + +
} - {form.formState.errors.link_vrbl_vl && ( + {form.formState.errors.link_vrbl_vl_cn && (

- {form.formState.errors.link_vrbl_vl.message} + {form.formState.errors.link_vrbl_vl_cn.message}

)}
@@ -292,7 +308,7 @@ function LinkParamsDialog({ selectedLink, form, insertLinkVrbl, dialogOpen, onOp ( diff --git a/apps/cs/src/pages/linkParams/ui/link-params-page.tsx b/apps/cs/src/pages/linkParams/ui/link-params-page.tsx index 001eb9953..8eba90176 100644 --- a/apps/cs/src/pages/linkParams/ui/link-params-page.tsx +++ b/apps/cs/src/pages/linkParams/ui/link-params-page.tsx @@ -1,4 +1,4 @@ -"use client"; +"use client"; import { useState, useMemo } from "react"; import { @@ -123,8 +123,8 @@ function LinkParamsPage() { mutationFn: async (data: LinkVrblFormData) => await LinkApi.insertLinkVrbl({ ...data, - link_sn: selectedLink.linkSn, - mdfr_id: userUniqId, + intg_link_sn: selectedLink.linkSn, + mdfr_uuid: userUniqId, }), onSuccess: async () => { // 쿼리 무효화를 통한 최신 데이터 가져오기 @@ -140,8 +140,8 @@ function LinkParamsPage() { mutationFn: async (data: LinkVrblFormData) => await LinkApi.updateLinkVrblInfo({ ...data, - link_sn: selectedLink.linkSn, - mdfr_id: userUniqId, + intg_link_sn: selectedLink.linkSn, + mdfr_uuid: userUniqId, }), onSuccess: async () => { await queryClient.invalidateQueries({ @@ -191,7 +191,7 @@ function LinkParamsPage() { const handleRowClick = async (link: Link) => { setSelectedLink({ - linkSn: link.link_sn, + linkSn: link.intg_link_sn, linkNm: link.link_nm, }); @@ -242,11 +242,11 @@ function LinkParamsPage() { if (linkVrblInfo) { let newData = { ...linkVrblInfo }; - if (linkVrblInfo.mdfr_id) { + if (linkVrblInfo.mdfr_uuid) { const userName = await fetchUserInfo(); newData = { ...linkVrblInfo, - mdfr_id: userName, + mdfr_uuid: userName, }; } diff --git a/apps/cs/src/pages/linkStats/ui/link-stats-page.tsx b/apps/cs/src/pages/linkStats/ui/link-stats-page.tsx index 19163d24c..503e925d7 100644 --- a/apps/cs/src/pages/linkStats/ui/link-stats-page.tsx +++ b/apps/cs/src/pages/linkStats/ui/link-stats-page.tsx @@ -1,4 +1,4 @@ -"use client"; +"use client"; import { useState, useEffect, useRef } from "react"; import dayjs from "dayjs"; @@ -255,7 +255,7 @@ function LinkStatsPage() { setLogQueryParam({ isSucc: "SUCC", linkNm: linkStatsList.linkSuccStats[index]?.link_nm, - linkSn: linkStatsList.linkSuccStats[index]?.link_sn, + linkSn: linkStatsList.linkSuccStats[index]?.intg_link_sn, }); } }; @@ -284,7 +284,7 @@ function LinkStatsPage() { setLogQueryParam({ isSucc: "FAIL", linkNm: linkStatsList.linkFailStats[index]?.link_nm, - linkSn: linkStatsList.linkFailStats[index]?.link_sn, + linkSn: linkStatsList.linkFailStats[index]?.intg_link_sn, }); } }; diff --git a/apps/cs/src/pages/linkTable/ui/link-table-dialog.tsx b/apps/cs/src/pages/linkTable/ui/link-table-dialog.tsx index be835872d..3517393b4 100644 --- a/apps/cs/src/pages/linkTable/ui/link-table-dialog.tsx +++ b/apps/cs/src/pages/linkTable/ui/link-table-dialog.tsx @@ -1,4 +1,4 @@ -'use client'; +'use client'; import { Dialog, @@ -61,13 +61,13 @@ function LinkTableDialog({ dialogOpen, onOpenChange, form, tableInfo, insertLink if (!isModifyMode) { insertLinkTableCol({ ...data, - link_sn: tableInfo.link_sn, + intg_link_sn: tableInfo.intg_link_sn, tbl_sn: tableInfo.tbl_sn, }); } else { updateLinkTableCol({ ...data, - link_sn: tableInfo.link_sn, + intg_link_sn: tableInfo.intg_link_sn, tbl_sn: tableInfo.tbl_sn, }); } @@ -92,16 +92,16 @@ function LinkTableDialog({ dialogOpen, onOpenChange, form, tableInfo, insertLink col_sn: '', sou_col_nm: '', sou_col_korn_nm: '', - sou_col_data_frm: '', + sou_col_frm_nm: '', sou_col_sz: null, trsf_col_nm: '', trsf_col_korn_nm: '', - trsf_col_data_frm: '', + trsf_col_frm_nm: '', trsf_col_sz: null, col_seq: null, pk_yn: 'N', mdfcn_dt: '', - mdfr_id: '', + mdfr_uuid: '', }); } @@ -216,7 +216,7 @@ function LinkTableDialog({ dialogOpen, onOpenChange, form, tableInfo, insertLink ( @@ -227,9 +227,9 @@ function LinkTableDialog({ dialogOpen, onOpenChange, form, tableInfo, insertLink autoComplete="off" /> - {form.formState.errors.sou_col_data_frm && ( + {form.formState.errors.sou_col_frm_nm && (

- {form.formState.errors.sou_col_data_frm.message} + {form.formState.errors.sou_col_frm_nm.message}

)}
@@ -349,7 +349,7 @@ function LinkTableDialog({ dialogOpen, onOpenChange, form, tableInfo, insertLink ( @@ -360,9 +360,9 @@ function LinkTableDialog({ dialogOpen, onOpenChange, form, tableInfo, insertLink autoComplete="off" /> - {form.formState.errors.trsf_col_data_frm && ( + {form.formState.errors.trsf_col_frm_nm && (

- {form.formState.errors.trsf_col_data_frm.message} + {form.formState.errors.trsf_col_frm_nm.message}

)}
@@ -444,7 +444,7 @@ function LinkTableDialog({ dialogOpen, onOpenChange, form, tableInfo, insertLink ( diff --git a/apps/cs/src/pages/linkTable/ui/link-table-page.tsx b/apps/cs/src/pages/linkTable/ui/link-table-page.tsx index 3ccee78e8..55e541fc4 100644 --- a/apps/cs/src/pages/linkTable/ui/link-table-page.tsx +++ b/apps/cs/src/pages/linkTable/ui/link-table-page.tsx @@ -1,4 +1,4 @@ -"use client"; +"use client"; import { useState, useMemo } from "react"; import { @@ -97,7 +97,7 @@ function LinkTablePage() { mutationFn: async (data: LinkTableColData) => await LinkApi.insertLinkTableCol({ ...data, - mdfr_id: userUniqId, + mdfr_uuid: userUniqId, }), onSuccess: async () => { if (selectedTableInfo) { @@ -113,10 +113,10 @@ function LinkTablePage() { }); const tableData = await LinkApi.getLinkTableInfo( - selectedTableInfo.link_sn, + selectedTableInfo.intg_link_sn, ); const tableColList = await LinkApi.getLinkTableColList( - selectedTableInfo.link_sn, + selectedTableInfo.intg_link_sn, ); setSelectedTableInfo(tableData); @@ -132,7 +132,7 @@ function LinkTablePage() { mutationFn: async (data: LinkTableColData) => await LinkApi.updateLinkTableCol({ ...data, - mdfr_id: userUniqId, + mdfr_uuid: userUniqId, }), onSuccess: async () => { if (selectedTableInfo) { @@ -148,10 +148,10 @@ function LinkTablePage() { }); const tableData = await LinkApi.getLinkTableInfo( - selectedTableInfo.link_sn, + selectedTableInfo.intg_link_sn, ); const tableColList = await LinkApi.getLinkTableColList( - selectedTableInfo.link_sn, + selectedTableInfo.intg_link_sn, ); setSelectedTableInfo(tableData); @@ -180,10 +180,10 @@ function LinkTablePage() { }); const tableData = await LinkApi.getLinkTableInfo( - selectedTableInfo.link_sn, + selectedTableInfo.intg_link_sn, ); const tableColList = await LinkApi.getLinkTableColList( - selectedTableInfo.link_sn, + selectedTableInfo.intg_link_sn, ); setSelectedTableInfo(tableData); @@ -212,14 +212,14 @@ function LinkTablePage() { }); const tableData = await LinkApi.getLinkTableInfo( - selectedTableInfo.link_sn, + selectedTableInfo.intg_link_sn, ); const tableColList = await LinkApi.getLinkTableColList( - selectedTableInfo.link_sn, + selectedTableInfo.intg_link_sn, ); tableForm.reset({ - link_sn: tableData.link_sn, + intg_link_sn: tableData.intg_link_sn, link_nm: tableData.link_nm, tbl_sn: tableData.tbl_sn ?? "", sou_tbl_nm: tableData.sou_tbl_nm ?? "", @@ -254,10 +254,10 @@ function LinkTablePage() { }); const tableData = await LinkApi.getLinkTableInfo( - selectedTableInfo.link_sn, + selectedTableInfo.intg_link_sn, ); const tableColList = await LinkApi.getLinkTableColList( - selectedTableInfo.link_sn, + selectedTableInfo.intg_link_sn, ); setSelectedTableInfo(tableData); @@ -316,15 +316,15 @@ function LinkTablePage() { }; const handleRowClick = async (data: Link) => { - const tableData = await LinkApi.getLinkTableInfo(data.link_sn); - const tableColList = await LinkApi.getLinkTableColList(data.link_sn); + const tableData = await LinkApi.getLinkTableInfo(data.intg_link_sn); + const tableColList = await LinkApi.getLinkTableColList(data.intg_link_sn); setSelectedTableInfo(tableData); setTableColList(tableColList.content); setSelectedColIds([]); tableForm.reset({ - link_sn: tableData.link_sn, + intg_link_sn: tableData.intg_link_sn, link_nm: tableData.link_nm, tbl_sn: tableData.tbl_sn ?? "", sou_tbl_nm: tableData.sou_tbl_nm ?? "", @@ -345,11 +345,11 @@ function LinkTablePage() { if (colInfo) { let newData = { ...colInfo }; - if (colInfo.mdfr_id) { + if (colInfo.mdfr_uuid) { const userName = await fetchUserInfo(); newData = { ...colInfo, - mdfr_id: userName, + mdfr_uuid: userName, }; } @@ -387,7 +387,7 @@ function LinkTablePage() { if (await confirm(confirmMsg)) { insertLinkTableInfo({ ...data, - mdfr_id: userUniqId, + mdfr_uuid: userUniqId, tbl_sn: regTblInfo.count > 0 ? regTblInfo.tbl_sn : "", }); } @@ -398,7 +398,7 @@ function LinkTablePage() { updateLinkTableInfo({ ...data, tbl_sn: regTblInfo.count > 0 ? regTblInfo.tbl_sn : "", - mdfr_id: userUniqId, + mdfr_uuid: userUniqId, }); } }); @@ -511,7 +511,7 @@ function LinkTablePage() { {selectedTableInfo ? ( ( From e8a5701e73af0a7e9598128fc3f7a75c2850d476 Mon Sep 17 00:00:00 2001 From: bicochan Date: Wed, 16 Sep 2026 17:37:44 +0900 Subject: [PATCH 04/20] =?UTF-8?q?[as]=20feat:=20=EC=9B=B9=EA=B8=B0?= =?UTF-8?q?=EC=95=88=EA=B8=B0=20=EB=8B=A4=EC=9D=B4=EC=96=BC=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=20=EB=82=B4=20=EA=B8=88=EC=95=A1=EA=B2=80=EC=A6=9D?= =?UTF-8?q?=EA=B2=B0=EA=B3=BC=20=EC=84=B9=EC=85=98=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/as/public/webhwpctrl/hwpsdkmain.html | 81 ++++++++++------ .../pwrk-cnsltn-doc-pjtco-ajmt-mng-service.ts | 24 +++++ .../api/queries.ts | 22 +++++ .../pwrk-cnsltn-doc-pjtco-ajmt-mng/index.ts | 10 ++ ...wrk-cnsltn-doc-pjtco-ajmt-mng-interface.ts | 44 +++++++++ .../lib/fnrs-cnsltn-regist-schema.ts | 4 +- .../components/pwrk-cnsltn-doc-mng-dialog.tsx | 78 ++++++++++++--- .../pwrk-cnsltn-doc-pjtco-ajmt-table.tsx | 97 +++++++++++++++++++ apps/as/src/shared/config/api.ts | 1 + apps/as/src/shared/model/pbadms-sprt.ts | 2 +- .../widgets/hangulgiangi/model/hwp-ctrl.ts | 1 + .../widgets/hangulgiangi/ui/hangul-giangi.tsx | 5 +- .../pbadms-sprt/lib/checklist-form-utils.ts | 6 +- 13 files changed, 325 insertions(+), 50 deletions(-) create mode 100644 apps/as/src/entities/pwrk-cnsltn-doc-pjtco-ajmt-mng/api/pwrk-cnsltn-doc-pjtco-ajmt-mng-service.ts create mode 100644 apps/as/src/entities/pwrk-cnsltn-doc-pjtco-ajmt-mng/api/queries.ts create mode 100644 apps/as/src/entities/pwrk-cnsltn-doc-pjtco-ajmt-mng/index.ts create mode 100644 apps/as/src/entities/pwrk-cnsltn-doc-pjtco-ajmt-mng/model/pwrk-cnsltn-doc-pjtco-ajmt-mng-interface.ts create mode 100644 apps/as/src/pages/fnrs-cnsltn/ui/components/pwrk-cnsltn-doc-pjtco-ajmt-table.tsx diff --git a/apps/as/public/webhwpctrl/hwpsdkmain.html b/apps/as/public/webhwpctrl/hwpsdkmain.html index d24c7eee7..3f4bc1526 100644 --- a/apps/as/public/webhwpctrl/hwpsdkmain.html +++ b/apps/as/public/webhwpctrl/hwpsdkmain.html @@ -6,36 +6,57 @@ - - - - Hwp SDK Wasm Sample - - - - - - - {isPjtcoAjmtTableOpen ? ( -
-
-

금액검증결과

- -
-
- -
-
- ) : ( - - )} + {pjtcoAjmtPage?.content?.length ? ( + isPjtcoAjmtTableOpen ? ( +
+
+

금액검증결과

+ +
+
+ +
+
+ ) : ( + + ) + ) : null} ) : null} From 41643563f801ab2d43a787a335f3d643538853ab Mon Sep 17 00:00:00 2001 From: bicochan Date: Thu, 17 Sep 2026 10:55:51 +0900 Subject: [PATCH 06/20] =?UTF-8?q?[as]=20chore:=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=EC=82=AC=ED=95=AD=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/as/src/pages/fnrs-cnsltn/model/columns.tsx | 8 ++++---- apps/as/src/pages/instl-sncn/model/columns.tsx | 4 ++-- apps/as/src/pages/sewer-bsc-plan/model/columns.tsx | 4 ++-- .../widgets/pbadms-sprt/ui/business-cost-form-section.tsx | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/as/src/pages/fnrs-cnsltn/model/columns.tsx b/apps/as/src/pages/fnrs-cnsltn/model/columns.tsx index fff55d21a..2374b0c40 100644 --- a/apps/as/src/pages/fnrs-cnsltn/model/columns.tsx +++ b/apps/as/src/pages/fnrs-cnsltn/model/columns.tsx @@ -12,7 +12,7 @@ const columnHelper = createColumnHelper(); const MAIN_STEP_LABELS = { apply: "재원협의 신청", - envoReview: "환경청 검토", + envoReview: "재원협의 검토", techReview: "기술검토", reply: "검토결과 회신", } as const; @@ -20,7 +20,7 @@ const MAIN_STEP_LABELS = { export const PROGRESS_STATUS_COLUMNS = [ { label: "재원협의 신청 (시군)", sttsComCd: "ST" }, { label: "재원협의 신청 (시도)", sttsComCd: "LE" }, - { label: "환경청 검토", sttsComCd: "ER" }, + { label: "재원협의 검토", sttsComCd: "ER" }, { label: "기술검토", sttsComCd: "TE" }, { label: "기술검토 회신", sttsComCd: "TP" }, { label: "환경청 검토 결과 회신", sttsComCd: "EP" }, @@ -61,7 +61,7 @@ function buildProgressBadges(prgrsSttsComCd: string, techRplyHstryYn: "Y" | "N") ]; } - if (prgrsSttsComCd === "ER" || prgrsSttsComCd === "TE" || prgrsSttsComCd === "SL") { + if (["FV", "ER", "AC", "TE", "RB", "RA", "AV", "EV", "RK", "RR", "SL"].includes(prgrsSttsComCd)) { return [ { label: MAIN_STEP_LABELS.apply, state: "completed" }, { label: MAIN_STEP_LABELS.envoReview, state: "completed" }, @@ -82,7 +82,7 @@ function buildProgressBadges(prgrsSttsComCd: string, techRplyHstryYn: "Y" | "N") ]; } - if (prgrsSttsComCd === "EP") { + if (prgrsSttsComCd === "EP" || prgrsSttsComCd === "TA") { return [ { label: MAIN_STEP_LABELS.apply, state: "completed" }, { label: MAIN_STEP_LABELS.envoReview, state: "completed" }, diff --git a/apps/as/src/pages/instl-sncn/model/columns.tsx b/apps/as/src/pages/instl-sncn/model/columns.tsx index 2dcca5c58..11d51de65 100644 --- a/apps/as/src/pages/instl-sncn/model/columns.tsx +++ b/apps/as/src/pages/instl-sncn/model/columns.tsx @@ -12,7 +12,7 @@ const columnHelper = createColumnHelper(); const MAIN_STEP_LABELS = { apply: "설치인가 신청", - envoReview: "환경청 검토", + envoReview: "설치인가 검토", techReview: "기술검토", reply: "검토결과 회신", } as const; @@ -20,7 +20,7 @@ const MAIN_STEP_LABELS = { export const PROGRESS_STATUS_COLUMNS = [ { label: "설치인가 신청 (시군)", sttsComCd: "ST" }, { label: "설치인가 신청 (시도)", sttsComCd: "LE" }, - { label: "환경청 검토", sttsComCd: "ER" }, + { label: "설치인가 검토", sttsComCd: "ER" }, { label: "기술검토", sttsComCd: "TE" }, { label: "기술검토 회신", sttsComCd: "TP" }, { label: "검토결과 회신", sttsComCd: "EP" }, diff --git a/apps/as/src/pages/sewer-bsc-plan/model/columns.tsx b/apps/as/src/pages/sewer-bsc-plan/model/columns.tsx index 4dc1af0c6..e75312b0b 100644 --- a/apps/as/src/pages/sewer-bsc-plan/model/columns.tsx +++ b/apps/as/src/pages/sewer-bsc-plan/model/columns.tsx @@ -12,14 +12,14 @@ const columnHelper = createColumnHelper(); const MAIN_STEP_LABELS = { apply: "기본계획 신청", - envoReview: "환경청 검토", + envoReview: "기본계획 검토", techReview: "기술검토", reply: "검토결과 회신", } as const; export const PROGRESS_STATUS_COLUMNS = [ { label: "기본계획 신청 (시군)", sttsComCd: "LE" }, - { label: "환경청 검토", sttsComCd: "ER" }, + { label: "기본계획 검토", sttsComCd: "ER" }, { label: "기술검토", sttsComCd: "TE" }, { label: "기술검토 회신", sttsComCd: "TP" }, { label: "횐경청 검토 결과 회신", sttsComCd: "EP" }, diff --git a/apps/as/src/widgets/pbadms-sprt/ui/business-cost-form-section.tsx b/apps/as/src/widgets/pbadms-sprt/ui/business-cost-form-section.tsx index 22aa35c82..15ff2a413 100644 --- a/apps/as/src/widgets/pbadms-sprt/ui/business-cost-form-section.tsx +++ b/apps/as/src/widgets/pbadms-sprt/ui/business-cost-form-section.tsx @@ -104,7 +104,7 @@ function BusinessCostFormSection() { const data = bizCstList[idx]; if (!data) return null; - const diff = (data.tstmDesignAmt || 0) - (data.bgtRfltAmt || 0); + const diff = (data.tstmDesignAmt || 0) - (data.bscPlanAmt || 0); const paddingLeft = `${item.level * 1.6}rem`; const showSubIcon = item.level >= 2; From 086d5a18e859ba6d4736294acee71d45560fdff4 Mon Sep 17 00:00:00 2001 From: bicochan Date: Thu, 17 Sep 2026 16:48:13 +0900 Subject: [PATCH 07/20] =?UTF-8?q?[as]=20chore:=20=EC=9E=AC=EC=9B=90?= =?UTF-8?q?=ED=98=91=EC=9D=98=20=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/as/src/entities/elapr/api/queries.ts | 3 +- .../elapr/ui/elapr-approval-dialog.tsx | 6 +- .../pages/fnrs-cnsltn/lib/button-config.ts | 15 ++--- .../ui/components/floating-action-buttons.tsx | 63 ++++++------------- .../components/pwrk-cnsltn-doc-mng-dialog.tsx | 10 +-- .../pwrk-cnsltn-rvw-rslt-inq-dialog.tsx | 14 ++--- .../pages/fnrs-cnsltn/ui/fnrs-form-page.tsx | 31 +++++++-- .../sections/tech-review-opinion-section.tsx | 3 +- apps/as/src/shared/model/pbadms-sprt.ts | 4 +- .../pbadms-sprt/lib/fnrs-shar-form-utils.ts | 10 +-- .../ui/business-cost-form-section.tsx | 10 +-- .../pbadms-sprt/ui/splmnt-dmnd-dialog.tsx | 6 +- 12 files changed, 81 insertions(+), 94 deletions(-) diff --git a/apps/as/src/entities/elapr/api/queries.ts b/apps/as/src/entities/elapr/api/queries.ts index 19f5fce9b..9908ef44f 100644 --- a/apps/as/src/entities/elapr/api/queries.ts +++ b/apps/as/src/entities/elapr/api/queries.ts @@ -187,13 +187,14 @@ export function useElaprDmnd(elaprDmndId: string | null | undefined) { export function useElaprDocPrgrsByDocNo( elaprDocNo: string | null | undefined, - options?: { elaprCycl?: number; enabled?: boolean }, + options?: { elaprCycl?: number; enabled?: boolean; structuralSharing?: boolean }, ) { const elaprCycl = options?.elaprCycl; return useQuery({ queryKey: [...elaprDmndBaseKey, "findDocPrgrsByDocNo", elaprDocNo, elaprCycl], queryFn: () => elaprDmndService.findDocPrgrsByDocNo(elaprDocNo!, elaprCycl), enabled: Boolean(elaprDocNo) && (options?.enabled ?? true), + structuralSharing: options?.structuralSharing ?? true, }); } diff --git a/apps/as/src/entities/elapr/ui/elapr-approval-dialog.tsx b/apps/as/src/entities/elapr/ui/elapr-approval-dialog.tsx index 0f7cfd056..ed8a5de01 100644 --- a/apps/as/src/entities/elapr/ui/elapr-approval-dialog.tsx +++ b/apps/as/src/entities/elapr/ui/elapr-approval-dialog.tsx @@ -71,6 +71,7 @@ function ElaprApprovalDialog({ const { data: elaprDocPrgrsList, isLoading } = useElaprDocPrgrsByDocNo(open ? elaprDocNo : null, { elaprCycl, + structuralSharing: false, }); const cyclDocPrgrsList = useMemo(() => { if (elaprCycl == null) return elaprDocPrgrsList; @@ -100,10 +101,7 @@ function ElaprApprovalDialog({ const savePrgrsSttsMutation = useSaveElaprPrgrsStts(); const sensors = useDndSensors(); - const currentUserPrgrs = findCurrentUserPendingApprovalRequest( - cyclDocPrgrsList, - currentUserUuid, - ); + const currentUserPrgrs = findCurrentUserPendingApprovalRequest(cyclDocPrgrsList, currentUserUuid); const canApprove = Boolean(currentUserPrgrs?.elaprPrgrsId); const pickingRow = pickingRowKey ? rows.find((r) => r.rowKey === pickingRowKey) : undefined; diff --git a/apps/as/src/pages/fnrs-cnsltn/lib/button-config.ts b/apps/as/src/pages/fnrs-cnsltn/lib/button-config.ts index 21c5ed562..8ec805852 100644 --- a/apps/as/src/pages/fnrs-cnsltn/lib/button-config.ts +++ b/apps/as/src/pages/fnrs-cnsltn/lib/button-config.ts @@ -2,11 +2,9 @@ export const FNRS_CNSLTN_VIEW_BUTTON_ACTION = { strg: "strg", aply: "aply", del: "del", - fnrsCnsltnAncmnt: "fnrsCnsltnAncmnt", envoSbmsn: "envoSbmsn", rjct: "rjct", sncnAprv: "sncnAprv", - lclRply: "lclRply", rvwRply: "rvwRply", rqstTechRvw: "rqstTechRvw", fileSplmnt: "fileSplmnt", @@ -39,14 +37,10 @@ const ROLE_STATUS_BUTTON_ACTIONS: Record([ + FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwRsltInq, + FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwStrg, FNRS_CNSLTN_VIEW_BUTTON_ACTION.dmndSplmnt, FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwCmptn, FNRS_CNSLTN_VIEW_BUTTON_ACTION.atrzAprv, 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 ccb066a51..7b776614d 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 @@ -262,19 +262,6 @@ function FloatingActionButtons({ router.push("/fnrs-cnsltn"); } - // async function handleFnrsCnsltnAncmntClick() { - // const payload: DocPrgrsUpdateRequestDto = { - // docNo, - // docSeComCd, - // prgrsSttsComCd: "TB", - // }; - // await executeAction({ - // action: FNRS_CNSLTN_VIEW_BUTTON_ACTION.fnrsCnsltnAncmnt, - // request: payload, - // successMessage: "고시되었습니다.", - // }); - // } - async function handleEnvoSbmsnClick() { const payload: DocPrgrsUpdateRequestDto = { docNo, @@ -288,19 +275,6 @@ function FloatingActionButtons({ }); } - async function handleLclRplyClick() { - const payload: DocPrgrsUpdateRequestDto = { - docNo, - docSeComCd, - prgrsSttsComCd: "RB", - }; - await executeAction({ - action: FNRS_CNSLTN_VIEW_BUTTON_ACTION.lclRply, - request: payload, - successMessage: "지자체 회신이 완료되었습니다.", - }); - } - async function handleRjctClick() { const payload: DocPrgrsUpdateRequestDto = { docNo, @@ -339,7 +313,7 @@ function FloatingActionButtons({ ); if (percent !== 100) { - alert("모든 체크리스트 항목을 체크해야 검토결과 회신이 가능합니다."); + alert("모든 체크리스트 항목을 체크해야 검토 결과 회신이 가능합니다."); return; } @@ -348,7 +322,7 @@ function FloatingActionButtons({ data, checklistFormState, "ENV", - isResultReply ? "EP" : "RM", + isResultReply ? "EP" : "RB", "CP", getReviewOpinionFormData(), opnrNm, @@ -357,21 +331,32 @@ function FloatingActionButtons({ await executeAction({ action: FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwRply, request: payload, - successMessage: isResultReply - ? "검토결과 회신이 완료되었습니다." - : "재원협의 결과 회신이 완료되었습니다.", + successMessage: "검토 결과 회신이 완료되었습니다.", }); techReviewOpinionRef?.current?.resetForm(); } async function handleRqstTechRvwClick() { + if (prgrsSttsComCd === "LE") { + const { percent } = computeReviewStepChecklistProgress( + data.cklstResultList ?? [], + checklistFormState.results, + "ENV", + ); + + if (percent !== 100) { + alert("모든 체크리스트 항목을 체크해야 기술 검토 의뢰가 가능합니다."); + return; + } + } + const payload: FnrsExamineRequestDto = { prgrsSttsComCd: "FV", }; await executeAction({ action: FNRS_CNSLTN_VIEW_BUTTON_ACTION.rqstTechRvw, request: payload, - successMessage: "기술검토 의뢰가 완료되었습니다.", + successMessage: "기술 검토 의뢰가 완료되었습니다.", }); } @@ -570,21 +555,11 @@ function FloatingActionButtons({ 삭제 )} - {/* {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.fnrsCnsltnAncmnt) && ( - - )} */} {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.envoSbmsn) && ( )} - {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.lclRply) && ( - - )} {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rjct) && ( )} {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rqstTechRvw) && ( @@ -858,11 +833,9 @@ const buttonActionHandlers: Record = strg: handleSaveApply, aply: handleSaveApply, del: handleDel, - fnrsCnsltnAncmnt: handleChangePrgrsSttsComCd, envoSbmsn: handleChangePrgrsSttsComCd, rjct: handleChangePrgrsSttsComCd, sncnAprv: handleChangePrgrsSttsComCd, - lclRply: handleChangePrgrsSttsComCd, rvwRply: handleTechReview, rqstTechRvw: handleRequestExamine, fileSplmnt: handleDmndSplmnt, diff --git a/apps/as/src/pages/fnrs-cnsltn/ui/components/pwrk-cnsltn-doc-mng-dialog.tsx b/apps/as/src/pages/fnrs-cnsltn/ui/components/pwrk-cnsltn-doc-mng-dialog.tsx index 3dfa33efb..040d3ec40 100644 --- a/apps/as/src/pages/fnrs-cnsltn/ui/components/pwrk-cnsltn-doc-mng-dialog.tsx +++ b/apps/as/src/pages/fnrs-cnsltn/ui/components/pwrk-cnsltn-doc-mng-dialog.tsx @@ -48,8 +48,8 @@ const VIEW_ONLY_PRGRS_STTS_COM_CDS = new Set(["RA", "RR", "EP", "TA"]); interface PwrkCnsltnDocMngDialogProps { open: boolean; fnrsCnsltnDocNo: string; - atrzSeComCdList: string[]; - prgrsSttsComCd: string; + atrzSeComCdList?: string[]; + prgrsSttsComCd?: string; canSave?: boolean; onClose: () => void; } @@ -257,8 +257,10 @@ function PwrkCnsltnDocMngDialog({ } const isAnyAtchUploading = uploadedFiles.some((item) => isUploading[item.fileKey]); - const viewOnly = VIEW_ONLY_PRGRS_STTS_COM_CDS.has(prgrsSttsComCd); - const canSaveByAtrz = !atrzSeComCdList.some((code) => APPROVER_ATRZ_SE_COM_CDS.has(code)); + const viewOnly = prgrsSttsComCd ? VIEW_ONLY_PRGRS_STTS_COM_CDS.has(prgrsSttsComCd) : false; + const canSaveByAtrz = atrzSeComCdList + ? !atrzSeComCdList.some((code) => APPROVER_ATRZ_SE_COM_CDS.has(code)) + : true; const canSave = !viewOnly && (canSaveProp ?? canSaveByAtrz); return ( diff --git a/apps/as/src/pages/fnrs-cnsltn/ui/components/pwrk-cnsltn-rvw-rslt-inq-dialog.tsx b/apps/as/src/pages/fnrs-cnsltn/ui/components/pwrk-cnsltn-rvw-rslt-inq-dialog.tsx index e811873f4..91a5896ff 100644 --- a/apps/as/src/pages/fnrs-cnsltn/ui/components/pwrk-cnsltn-rvw-rslt-inq-dialog.tsx +++ b/apps/as/src/pages/fnrs-cnsltn/ui/components/pwrk-cnsltn-rvw-rslt-inq-dialog.tsx @@ -96,7 +96,7 @@ function PwrkCnsltnRvwRsltInqDialog({ aria-describedby={undefined} > - 검토결과조회 + 검토 결과 조회 {isLoading ? ( @@ -159,9 +159,9 @@ function CnsltnListTable({ return ( - - - + + + @@ -172,7 +172,7 @@ function CnsltnListTable({ aria-label="전체 선택" /> - 분류 + 구분 검토의견 @@ -194,8 +194,8 @@ function CnsltnListTable({ aria-label="행 선택" /> - -

{formatOptional(row.rmrk)}

+ +

{formatOptional(row.rvwOpnnSn)}

{formatOptional(row.rvwOpnn)}

diff --git a/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-form-page.tsx b/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-form-page.tsx index 671b70f98..632c51e3b 100644 --- a/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-form-page.tsx +++ b/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-form-page.tsx @@ -47,6 +47,7 @@ import { import { getCreateDefaultValues, mapDetailToFormData } from "../lib/form-data-mapper"; import { PROGRESS_STATUS_COLUMNS } from "../model/columns"; +import { PwrkCnsltnDocMngDialog } from "./components/pwrk-cnsltn-doc-mng-dialog"; import { BasicInfoFormSection } from "./sections/basic-info-form-section"; interface FnrsFormPageProps { mode: "create" | "edit"; @@ -66,8 +67,10 @@ function FnrsFormPage({ mode, initialData, createDefaults }: FnrsFormPageProps) const userInfo = useUserStore((state) => state.userInfo); const alert = useAlertStore((state) => state.setMessage); const [isSubmitting, setIsSubmitting] = useState(false); + const [isPwrkCnsltnDocMngOpen, setIsPwrkCnsltnDocMngOpen] = useState(false); const isEditMode = mode === "edit"; const isSplmntPrgrsStts = initialData?.detDto?.prgrsSttsComCd === "SL"; + const fnrsCnsltnDocNo = initialData?.detDto?.fnrsCnsltnDocNo; const { data: masterSharTree = [] } = useFnrsSharSeMngTree(); const { data: acntgTree = [] } = useAcntgSeMngTree(); @@ -156,7 +159,7 @@ function FnrsFormPage({ mode, initialData, createDefaults }: FnrsFormPageProps) (item) => !item.splmntCn || !item.splmntCn.trim(), ); if (hasEmptySplmntCn) { - alert("보완요청내용이 있습니다. 보완완료내용을 입력해 주세요."); + alert("보완요청내용이 있습니다. 보완 완료내용을 입력해 주세요."); return; } @@ -171,12 +174,12 @@ function FnrsFormPage({ mode, initialData, createDefaults }: FnrsFormPageProps) const result = await submitSupplementForm(data); if (!result) return; - alert("보완완료 처리되었습니다."); + alert("보완 완료 처리되었습니다."); await queryClient.invalidateQueries({ queryKey: fnrsCnsltnKeys.all }); router.push(`/fnrs-cnsltn/${docNo}`); } catch (error) { - console.error("보완완료 실패:", error); - alert("보완완료 처리 중 오류가 발생했습니다."); + console.error("보완 완료 실패:", error); + alert("보완 완료 처리 중 오류가 발생했습니다."); } finally { setIsSubmitting(false); } @@ -334,14 +337,32 @@ function FnrsFormPage({ mode, initialData, createDefaults }: FnrsFormPageProps) onClick={form.handleSubmit(onSplmntCmptn)} disabled={isSubmitting} > - 보완완료 + 보완 완료 )} + {isSplmntPrgrsStts && fnrsCnsltnDocNo ? ( + + ) : null} + {fnrsCnsltnDocNo ? ( + setIsPwrkCnsltnDocMngOpen(false)} + /> + ) : null} ); } diff --git a/apps/as/src/pages/fnrs-cnsltn/ui/sections/tech-review-opinion-section.tsx b/apps/as/src/pages/fnrs-cnsltn/ui/sections/tech-review-opinion-section.tsx index caa4a3ada..837a97239 100644 --- a/apps/as/src/pages/fnrs-cnsltn/ui/sections/tech-review-opinion-section.tsx +++ b/apps/as/src/pages/fnrs-cnsltn/ui/sections/tech-review-opinion-section.tsx @@ -136,8 +136,7 @@ const TechReviewOpinionSection = forwardRef< const kecoRvwList = rvwList.filter((item) => item.opnrSeComCd === "KECO"); const hasEnvSection = envRvwList.length > 0 || editableReviewStep === "ENV"; - const hasKecoSection = - kecoRvwList.length > 0 || (editableReviewStep === "KECO" && canWriteKecoOpinion); + const hasKecoSection = kecoRvwList.length > 0 || editableReviewStep === "KECO"; if (!hasEnvSection && !hasKecoSection) { return null; diff --git a/apps/as/src/shared/model/pbadms-sprt.ts b/apps/as/src/shared/model/pbadms-sprt.ts index 77a346522..959c8133d 100644 --- a/apps/as/src/shared/model/pbadms-sprt.ts +++ b/apps/as/src/shared/model/pbadms-sprt.ts @@ -54,9 +54,9 @@ export interface BizCstTreeDto { bscPlanAmt: number; /** 금회설계금액(C) */ tstmDesignAmt: number; - /** 증감금액(금회설계금액 - 표준사업비, C-B) */ + /** 증감금액(금회설계금액 - 예산반영금액, C-A) */ chgAmt: number; - /** 증감율 % ((증감금액 / 표준사업비) * 100) */ + /** 증감율 % ((증감금액 / 예산반영금액(A)) * 100) */ chgRt: number; } diff --git a/apps/as/src/widgets/pbadms-sprt/lib/fnrs-shar-form-utils.ts b/apps/as/src/widgets/pbadms-sprt/lib/fnrs-shar-form-utils.ts index 4700fdac1..d593d4aee 100644 --- a/apps/as/src/widgets/pbadms-sprt/lib/fnrs-shar-form-utils.ts +++ b/apps/as/src/widgets/pbadms-sprt/lib/fnrs-shar-form-utils.ts @@ -122,7 +122,7 @@ function findBizCstSyncItem(costItems: CostItemDef[]): CostItemDef | undefined { } export interface BizCstTotalAmounts { - bscPlanAmt: number; + bgtRfltAmt: number; tstmDesignAmt: number; } @@ -136,13 +136,13 @@ export function getBizCstTotalRow( costItems: CostItemDef[], ): BizCstTotalAmounts { const syncCostItem = findBizCstSyncItem(costItems); - if (!syncCostItem) return { bscPlanAmt: 0, tstmDesignAmt: 0 }; + if (!syncCostItem) return { bgtRfltAmt: 0, tstmDesignAmt: 0 }; const costRow = bizCstList.find((item) => item.acntgSeCd === syncCostItem.code); - if (!costRow) return { bscPlanAmt: 0, tstmDesignAmt: 0 }; + if (!costRow) return { bgtRfltAmt: 0, tstmDesignAmt: 0 }; return { - bscPlanAmt: costRow.bscPlanAmt || 0, + bgtRfltAmt: costRow.bgtRfltAmt || 0, tstmDesignAmt: costRow.tstmDesignAmt || 0, }; } @@ -178,7 +178,7 @@ export function calcBizCstSharRemaining( const leafSum = sumFnrsSharLeafAmounts(sharList, sharItems); return { - exstnRemaining: roundAmount(bizCstTotal.bscPlanAmt - leafSum.exstnAmt), + exstnRemaining: roundAmount(bizCstTotal.bgtRfltAmt - leafSum.exstnAmt), chgRqtRemaining: roundAmount(bizCstTotal.tstmDesignAmt - leafSum.chgRqtAmt), }; } diff --git a/apps/as/src/widgets/pbadms-sprt/ui/business-cost-form-section.tsx b/apps/as/src/widgets/pbadms-sprt/ui/business-cost-form-section.tsx index 15ff2a413..dc50504a5 100644 --- a/apps/as/src/widgets/pbadms-sprt/ui/business-cost-form-section.tsx +++ b/apps/as/src/widgets/pbadms-sprt/ui/business-cost-form-section.tsx @@ -104,7 +104,7 @@ function BusinessCostFormSection() { const data = bizCstList[idx]; if (!data) return null; - const diff = (data.tstmDesignAmt || 0) - (data.bscPlanAmt || 0); + const diff = (data.tstmDesignAmt || 0) - (data.bgtRfltAmt || 0); const paddingLeft = `${item.level * 1.6}rem`; const showSubIcon = item.level >= 2; @@ -120,14 +120,14 @@ function BusinessCostFormSection() { ( handleCostChange(idx, "bscPlanAmt", e.target.value)} + onChange={(e) => handleCostChange(idx, "bgtRfltAmt", e.target.value)} readOnly={item.readonly} aria-invalid={fieldState.invalid} className={`text-right ${item.readonly ? "bg-muted" : ""}`} @@ -138,14 +138,14 @@ function BusinessCostFormSection() { ( handleCostChange(idx, "bgtRfltAmt", e.target.value)} + onChange={(e) => handleCostChange(idx, "bscPlanAmt", e.target.value)} readOnly={item.readonly} aria-invalid={fieldState.invalid} className={`text-right ${item.readonly ? "bg-muted" : ""}`} diff --git a/apps/as/src/widgets/pbadms-sprt/ui/splmnt-dmnd-dialog.tsx b/apps/as/src/widgets/pbadms-sprt/ui/splmnt-dmnd-dialog.tsx index 752898721..2e225a286 100644 --- a/apps/as/src/widgets/pbadms-sprt/ui/splmnt-dmnd-dialog.tsx +++ b/apps/as/src/widgets/pbadms-sprt/ui/splmnt-dmnd-dialog.tsx @@ -199,7 +199,7 @@ function SplmntDmndDialog({ try { await attachService.deleteAttachmentByAtflId(atflId); } catch (error) { - console.error("보완요청 첨부파일 삭제 실패:", error); + console.error("보완 요청 첨부파일 삭제 실패:", error); } } @@ -226,7 +226,7 @@ function SplmntDmndDialog({ - 보완요청 + 보완 요청
@@ -322,7 +322,7 @@ function SplmntDmndDialog({ 취소 From 43bc7db7d5933add8927f7f47e623901c42e2819 Mon Sep 17 00:00:00 2001 From: bicochan Date: Thu, 17 Sep 2026 17:04:31 +0900 Subject: [PATCH 08/20] =?UTF-8?q?[as]=20chore:=20useAplnRows=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/as/src/entities/elapr/lib/use-apln-rows.ts | 4 ++-- .../src/pages/approval-line-management/ui/elapr-apln-grid.tsx | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/as/src/entities/elapr/lib/use-apln-rows.ts b/apps/as/src/entities/elapr/lib/use-apln-rows.ts index dfa731d07..576b722b4 100644 --- a/apps/as/src/entities/elapr/lib/use-apln-rows.ts +++ b/apps/as/src/entities/elapr/lib/use-apln-rows.ts @@ -24,7 +24,7 @@ function toRow(item: ElaprApln): ElaprAplnRow { interface UseAplnRowsOptions { seedKey: string | null; serverRows: ElaprApln[] | undefined; - elaprTmpltId?: string; + elaprTmpltId?: string | null; } export function createDraftRowKey(): string { @@ -58,7 +58,7 @@ export function useAplnRows({ seedKey, serverRows, elaprTmpltId = "" }: UseAplnR ...prev, { rowKey, - elaprTmpltId, + elaprTmpltId: elaprTmpltId ?? "", atrzSeComCd: "", aprvrUuid: "", aprvrNm: "", diff --git a/apps/as/src/pages/approval-line-management/ui/elapr-apln-grid.tsx b/apps/as/src/pages/approval-line-management/ui/elapr-apln-grid.tsx index e703551d5..5873803da 100644 --- a/apps/as/src/pages/approval-line-management/ui/elapr-apln-grid.tsx +++ b/apps/as/src/pages/approval-line-management/ui/elapr-apln-grid.tsx @@ -68,6 +68,7 @@ function ElaprAplnGrid({ elaprTmpltId }: ElaprAplnGridProps) { markDeleted, reorderRows, } = useAplnRows({ + seedKey: elaprTmpltId, elaprTmpltId, serverRows: aplnQuery.data?.content, }); From cc3bc548c9995efc701eb8bafc116267f516e032 Mon Sep 17 00:00:00 2001 From: bicochan Date: Fri, 18 Sep 2026 16:27:51 +0900 Subject: [PATCH 09/20] =?UTF-8?q?[as]=20feat:=20=EC=9E=AC=EC=9B=90?= =?UTF-8?q?=ED=98=91=EC=9D=98=20=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../elapr/ui/elapr-apln-picker-grid.tsx | 7 +-- .../pages/fnrs-cnsltn/lib/button-config.ts | 27 +++++++--- .../ui/components/floating-action-buttons.tsx | 53 ++++++++++++++++--- .../components/pwrk-cnsltn-doc-mng-dialog.tsx | 4 +- .../pwrk-cnsltn-doc-pjtco-ajmt-table.tsx | 12 ++++- apps/as/src/shared/ui/uploaded-file-chip.tsx | 2 +- 6 files changed, 86 insertions(+), 19 deletions(-) diff --git a/apps/as/src/entities/elapr/ui/elapr-apln-picker-grid.tsx b/apps/as/src/entities/elapr/ui/elapr-apln-picker-grid.tsx index 7f7a88911..c8c84e1c6 100644 --- a/apps/as/src/entities/elapr/ui/elapr-apln-picker-grid.tsx +++ b/apps/as/src/entities/elapr/ui/elapr-apln-picker-grid.tsx @@ -90,6 +90,7 @@ function ElaprAplnPickerGrid({ ? isExternalLoading : aplnQuery.isPending && Boolean(elaprTmpltId); const pickingRow = pickingRowKey ? rows.find((r) => r.rowKey === pickingRowKey) : undefined; + const excludedVisibleRows = visibleRows.filter((r) => r.atrzSeComCd !== "ATRZ01"); function handleDragEnd(event: DragEndEvent) { const { active, over } = event; @@ -149,7 +150,7 @@ function ElaprAplnPickerGrid({
) : !isReady ? (

결재서식을 선택하세요.

- ) : visibleRows.length === 0 ? ( + ) : excludedVisibleRows.length === 0 ? (

등록된 결재선이 없습니다. [결재선 추가]로 결재자를 등록하세요.

@@ -174,10 +175,10 @@ function ElaprAplnPickerGrid({ r.rowKey)} + items={excludedVisibleRows.map((r) => r.rowKey)} strategy={verticalListSortingStrategy} > - {visibleRows.map((row, index) => ( + {excludedVisibleRows.map((row, index) => ( { if (needsAtrzResolve && isRvwLoginUserLoading) return []; @@ -317,12 +319,11 @@ function FloatingActionButtons({ return; } - const isResultReply = prgrsSttsComCd === "RR"; const payload = buildTechReviewReplyPayload( data, checklistFormState, "ENV", - isResultReply ? "EP" : "RB", + "EP", "CP", getReviewOpinionFormData(), opnrNm, @@ -336,6 +337,36 @@ function FloatingActionButtons({ techReviewOpinionRef?.current?.resetForm(); } + async function handleRvwOpnnRplyClick() { + const { percent } = computeReviewStepChecklistProgress( + data.cklstResultList ?? [], + checklistFormState.results, + "ENV", + ); + + if (percent !== 100) { + alert("모든 체크리스트 항목을 체크해야 검토 의견 회신이 가능합니다."); + return; + } + + const payload = buildTechReviewReplyPayload( + data, + checklistFormState, + "ENV", + "RB", + "CP", + getReviewOpinionFormData(), + opnrNm, + ); + + await executeAction({ + action: FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwOpnnRply, + request: payload, + successMessage: "검토 의견 회신이 완료되었습니다.", + }); + techReviewOpinionRef?.current?.resetForm(); + } + async function handleRqstTechRvwClick() { if (prgrsSttsComCd === "LE") { const { percent } = computeReviewStepChecklistProgress( @@ -365,7 +396,7 @@ function FloatingActionButtons({ await executeAction({ action: FNRS_CNSLTN_VIEW_BUTTON_ACTION.rqstActnRvw, request: payload, - successMessage: "조치결과 검토의뢰가 완료되었습니다.", + successMessage: "조치 결과 검토 의뢰가 완료되었습니다.", }); } @@ -570,6 +601,11 @@ function FloatingActionButtons({ 결과 회신 )} + {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwOpnnRply) && ( + + )} {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwRply) && ( )} {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.fileSplmnt) && ( @@ -698,7 +734,11 @@ function FloatingActionButtons({ fnrsCnsltnDocNo={docNo} atrzSeComCdList={atrzSeComCdList} prgrsSttsComCd={prgrsSttsComCd} - canSave={needsElaprPrgrsCheck && !hasPendingApprovalRequest ? false : undefined} + canSave={ + (needsElaprPrgrsCheck && !hasPendingApprovalRequest) || viewOnlyPwrkCnsltnDoc + ? false + : null + } onClose={() => setActiveDialog(null)} /> @@ -837,6 +877,7 @@ const buttonActionHandlers: Record = rjct: handleChangePrgrsSttsComCd, sncnAprv: handleChangePrgrsSttsComCd, rvwRply: handleTechReview, + rvwOpnnRply: handleTechReview, rqstTechRvw: handleRequestExamine, fileSplmnt: handleDmndSplmnt, dsgntRvwr: handleDsgntRvwr, diff --git a/apps/as/src/pages/fnrs-cnsltn/ui/components/pwrk-cnsltn-doc-mng-dialog.tsx b/apps/as/src/pages/fnrs-cnsltn/ui/components/pwrk-cnsltn-doc-mng-dialog.tsx index 040d3ec40..a740f7356 100644 --- a/apps/as/src/pages/fnrs-cnsltn/ui/components/pwrk-cnsltn-doc-mng-dialog.tsx +++ b/apps/as/src/pages/fnrs-cnsltn/ui/components/pwrk-cnsltn-doc-mng-dialog.tsx @@ -43,14 +43,14 @@ const PWRK_ATCH_FILE_KEY_PREFIX = "pwrk-cnsltn-doc::"; const APPROVER_ATRZ_SE_COM_CDS = new Set(["ATRZ03", "ATRZ99"]); -const VIEW_ONLY_PRGRS_STTS_COM_CDS = new Set(["RA", "RR", "EP", "TA"]); +const VIEW_ONLY_PRGRS_STTS_COM_CDS = new Set(["TP", "RA", "RR", "EP", "TA"]); interface PwrkCnsltnDocMngDialogProps { open: boolean; fnrsCnsltnDocNo: string; atrzSeComCdList?: string[]; prgrsSttsComCd?: string; - canSave?: boolean; + canSave?: boolean | null; onClose: () => void; } diff --git a/apps/as/src/pages/fnrs-cnsltn/ui/components/pwrk-cnsltn-doc-pjtco-ajmt-table.tsx b/apps/as/src/pages/fnrs-cnsltn/ui/components/pwrk-cnsltn-doc-pjtco-ajmt-table.tsx index cc0c9ba35..bd1cf6120 100644 --- a/apps/as/src/pages/fnrs-cnsltn/ui/components/pwrk-cnsltn-doc-pjtco-ajmt-table.tsx +++ b/apps/as/src/pages/fnrs-cnsltn/ui/components/pwrk-cnsltn-doc-pjtco-ajmt-table.tsx @@ -43,11 +43,21 @@ function PwrkCnsltnDocPjtcoAjmtTable({ return (
+ + + + + 구분 검증결과 - 검증금액 + +
+ 검증금액 + (단위: 백만 원) +
+
diff --git a/apps/as/src/shared/ui/uploaded-file-chip.tsx b/apps/as/src/shared/ui/uploaded-file-chip.tsx index a7eb6fa22..82be5d581 100644 --- a/apps/as/src/shared/ui/uploaded-file-chip.tsx +++ b/apps/as/src/shared/ui/uploaded-file-chip.tsx @@ -12,7 +12,7 @@ interface UploadedFileChipProps { function UploadedFileChip({ fileName, isUploading = false, onRemove }: UploadedFileChipProps) { return ( -
+
{fileName} From f40d6fd5e862fdeb44a7951ab99746bcfc63310c Mon Sep 17 00:00:00 2001 From: bicochan Date: Fri, 18 Sep 2026 16:51:00 +0900 Subject: [PATCH 10/20] =?UTF-8?q?[as]=20feat:=20AttachmentDownloadLink=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?=EB=B0=8F=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/as/src/entities/attach/index.ts | 4 ++ .../attach/ui/attachment-download-link.tsx | 54 +++++++++++++++++++ .../sections/tech-review-opinion-section.tsx | 18 ++----- .../sections/tech-review-opinion-section.tsx | 18 ++----- .../sections/tech-review-opinion-section.tsx | 18 ++----- .../sections/tech-review-opinion-section.tsx | 18 ++----- .../ui/sections/tmplnt-section.tsx | 17 +++--- .../ui/attachments-view-section.tsx | 31 ++++------- .../ui/splmnt-dmnd-form-section.tsx | 12 ++--- .../ui/supplement-demand-section.tsx | 28 ++++------ 10 files changed, 109 insertions(+), 109 deletions(-) create mode 100644 apps/as/src/entities/attach/ui/attachment-download-link.tsx diff --git a/apps/as/src/entities/attach/index.ts b/apps/as/src/entities/attach/index.ts index ca804b4a0..69b220102 100644 --- a/apps/as/src/entities/attach/index.ts +++ b/apps/as/src/entities/attach/index.ts @@ -6,3 +6,7 @@ export { } from "./api/queries"; export { parseFilenameFromResponse } from "./lib/parse-filename-from-response"; export type { Attach, AttachService } from "./model/attach-interface"; +export { + AttachmentDownloadLink, + type AttachmentDownloadLinkProps, +} from "./ui/attachment-download-link"; diff --git a/apps/as/src/entities/attach/ui/attachment-download-link.tsx b/apps/as/src/entities/attach/ui/attachment-download-link.tsx new file mode 100644 index 000000000..85aab6ec5 --- /dev/null +++ b/apps/as/src/entities/attach/ui/attachment-download-link.tsx @@ -0,0 +1,54 @@ +"use client"; + +import { Paperclip } from "lucide-react"; + +import { cn } from "@common/components"; + +import { useDownloadAttachmentByAtflCd, useDownloadAttachmentByAtflId } from "../api/queries"; + +interface AttachmentDownloadLinkProps { + atflCd?: string; + atflId?: string; + fileName?: string; + className?: string; +} + +function AttachmentDownloadLink({ + atflCd, + atflId, + fileName, + className, +}: AttachmentDownloadLinkProps) { + const downloadByAtflCd = useDownloadAttachmentByAtflCd(); + const downloadByAtflId = useDownloadAttachmentByAtflId(); + const displayName = fileName || "첨부파일"; + const canDownload = Boolean(atflId || atflCd); + const isPending = atflId ? downloadByAtflId.isPending : downloadByAtflCd.isPending; + + function handleClick() { + if (atflId) { + downloadByAtflId.mutate(atflId); + return; + } + if (atflCd) downloadByAtflCd.mutate(atflCd); + } + + return ( + + ); +} + +export { AttachmentDownloadLink }; +export type { AttachmentDownloadLinkProps }; diff --git a/apps/as/src/pages/design-cnstn/ui/sections/tech-review-opinion-section.tsx b/apps/as/src/pages/design-cnstn/ui/sections/tech-review-opinion-section.tsx index d467bdb31..f81f0aaf9 100644 --- a/apps/as/src/pages/design-cnstn/ui/sections/tech-review-opinion-section.tsx +++ b/apps/as/src/pages/design-cnstn/ui/sections/tech-review-opinion-section.tsx @@ -2,14 +2,11 @@ import { forwardRef, useEffect, useImperativeHandle, useState } from "react"; -import { Paperclip } from "lucide-react"; - -import { PROXY_HOST } from "@/shared/config"; import { dayjs, getDefaultFileKey, useTus } from "@/shared/lib"; import { TextShimmer } from "@/shared/ui"; import { SectionCollapsible } from "@/shared/ui"; import { Field, FieldLabel, FieldSet } from "@/shared/ui/field"; -import { attachService } from "@/entities/attach"; +import { AttachmentDownloadLink, attachService } from "@/entities/attach"; import type { DesignCnstnRvwOpnnResponseDto } from "@/entities/design-cnstn"; import { Button, @@ -319,15 +316,10 @@ function TechReviewOpinionTable({ items }: TechReviewOpinionTableProps) { {item.atchFileInfo?.atflCd ? ( - - - {item.atchFileInfo.orgnlFileNm || "다운로드"} - + ) : ( "-" )} diff --git a/apps/as/src/pages/fnrs-cnsltn/ui/sections/tech-review-opinion-section.tsx b/apps/as/src/pages/fnrs-cnsltn/ui/sections/tech-review-opinion-section.tsx index 837a97239..a4c41d527 100644 --- a/apps/as/src/pages/fnrs-cnsltn/ui/sections/tech-review-opinion-section.tsx +++ b/apps/as/src/pages/fnrs-cnsltn/ui/sections/tech-review-opinion-section.tsx @@ -2,13 +2,10 @@ import { forwardRef, useEffect, useImperativeHandle, useState } from "react"; -import { Paperclip } from "lucide-react"; - -import { PROXY_HOST } from "@/shared/config"; import { dayjs, getDefaultFileKey, useTus } from "@/shared/lib"; import { AttachmentFileField, SectionCollapsible } from "@/shared/ui"; import { Field, FieldLabel, FieldSet } from "@/shared/ui/field"; -import { attachService } from "@/entities/attach"; +import { AttachmentDownloadLink, attachService } from "@/entities/attach"; import type { FnrsCnsltnRvwOpnnResponseDto } from "@/entities/fnrs-cnsltn"; import { RadioGroup, @@ -320,15 +317,10 @@ function TechReviewOpinionTable({ items }: TechReviewOpinionTableProps) { {item.atchFileInfo?.atflCd ? ( - - - {item.atchFileInfo.orgnlFileNm || "다운로드"} - + ) : ( "-" )} diff --git a/apps/as/src/pages/instl-sncn/ui/sections/tech-review-opinion-section.tsx b/apps/as/src/pages/instl-sncn/ui/sections/tech-review-opinion-section.tsx index ba787fd61..316c62d96 100644 --- a/apps/as/src/pages/instl-sncn/ui/sections/tech-review-opinion-section.tsx +++ b/apps/as/src/pages/instl-sncn/ui/sections/tech-review-opinion-section.tsx @@ -2,14 +2,11 @@ import { forwardRef, useEffect, useImperativeHandle, useState } from "react"; -import { Paperclip } from "lucide-react"; - -import { PROXY_HOST } from "@/shared/config"; import { dayjs, getDefaultFileKey, useTus } from "@/shared/lib"; import { TextShimmer } from "@/shared/ui"; import { SectionCollapsible } from "@/shared/ui"; import { Field, FieldLabel, FieldSet } from "@/shared/ui/field"; -import { attachService } from "@/entities/attach"; +import { AttachmentDownloadLink, attachService } from "@/entities/attach"; import type { InstlSncnRvwOpnnResponseDto, ReviewStepCode } from "@/entities/instl-sncn"; import { Button, @@ -331,15 +328,10 @@ function TechReviewOpinionTable({ items }: TechReviewOpinionTableProps) { {item.atchFileInfo?.atflCd ? ( - - - {item.atchFileInfo.orgnlFileNm || "다운로드"} - + ) : ( "-" )} diff --git a/apps/as/src/pages/sewer-bsc-plan/ui/sections/tech-review-opinion-section.tsx b/apps/as/src/pages/sewer-bsc-plan/ui/sections/tech-review-opinion-section.tsx index 1781f183e..f7371c342 100644 --- a/apps/as/src/pages/sewer-bsc-plan/ui/sections/tech-review-opinion-section.tsx +++ b/apps/as/src/pages/sewer-bsc-plan/ui/sections/tech-review-opinion-section.tsx @@ -2,14 +2,11 @@ import { forwardRef, useEffect, useImperativeHandle, useState } from "react"; -import { Paperclip } from "lucide-react"; - -import { PROXY_HOST } from "@/shared/config"; import { dayjs, getDefaultFileKey, useTus } from "@/shared/lib"; import { TextShimmer } from "@/shared/ui"; import { SectionCollapsible } from "@/shared/ui"; import { Field, FieldLabel, FieldSet } from "@/shared/ui/field"; -import { attachService } from "@/entities/attach"; +import { AttachmentDownloadLink, attachService } from "@/entities/attach"; import type { SewerBscPlanRvwOpnnResponseDto } from "@/entities/sewer-bsc-plan"; import { Button, @@ -338,15 +335,10 @@ function TechReviewOpinionTable({ items }: TechReviewOpinionTableProps) { {item.atchFileInfo?.atflCd ? ( - - - {item.atchFileInfo.orgnlFileNm || "다운로드"} - + ) : ( "-" )} diff --git a/apps/as/src/pages/sewer-bsc-plan/ui/sections/tmplnt-section.tsx b/apps/as/src/pages/sewer-bsc-plan/ui/sections/tmplnt-section.tsx index 7f87254d3..a2b4f8fa5 100644 --- a/apps/as/src/pages/sewer-bsc-plan/ui/sections/tmplnt-section.tsx +++ b/apps/as/src/pages/sewer-bsc-plan/ui/sections/tmplnt-section.tsx @@ -2,10 +2,8 @@ import { useMemo, useState } from "react"; -import { Paperclip } from "lucide-react"; - import { SectionCollapsible } from "@/shared/ui"; -import { useDownloadAttachmentByAtflCd } from "@/entities/attach"; +import { AttachmentDownloadLink } from "@/entities/attach"; import { useFacilityList } from "@/entities/bns-if"; import { useNowDmgMtncGnsvy } from "@/entities/dc"; import type { @@ -176,7 +174,6 @@ function TmplntFacilityMatrix({ } function TmplntSection({ tmplntList, det, dtl }: TmplntSectionProps) { - const { mutate: downloadAttachment } = useDownloadAttachmentByAtflCd(); const [selectedCode, setSelectedCode] = useState(tmplntList[0]?.swtrmtFcltCd ?? ""); const { data: facilityListData } = useFacilityList( { sido: det.sido ?? "", gugun: det.gugun ?? "" }, @@ -261,13 +258,11 @@ function TmplntSection({ tmplntList, det, dtl }: TmplntSectionProps) { {facilityName} 계획평면도 {item.atchFileGroupId ? ( - downloadAttachment(item.atchFileGroupId ?? "")} - > - - {item.atchFileInfo?.orgnlFileNm || "다운로드"} - + ) : ( "-" )} diff --git a/apps/as/src/widgets/pbadms-sprt/ui/attachments-view-section.tsx b/apps/as/src/widgets/pbadms-sprt/ui/attachments-view-section.tsx index 4a49e5855..2a492fd56 100644 --- a/apps/as/src/widgets/pbadms-sprt/ui/attachments-view-section.tsx +++ b/apps/as/src/widgets/pbadms-sprt/ui/attachments-view-section.tsx @@ -1,11 +1,9 @@ "use client"; -import { Paperclip } from "lucide-react"; - import { formatFileSize } from "@/shared/lib/file-utils"; import type { AtflMngClientResponseDto, EsntlAtchFileMngTreeResponseDto } from "@/shared/model"; import { SectionCollapsible } from "@/shared/ui"; -import { useDownloadAttachmentByAtflCd, useDownloadAttachmentByAtflId } from "@/entities/attach"; +import { AttachmentDownloadLink } from "@/entities/attach"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@common/components"; interface AttachmentsViewSectionProps { @@ -14,9 +12,6 @@ interface AttachmentsViewSectionProps { } function AttachmentsViewSection({ esntlFileList, etcFileList }: AttachmentsViewSectionProps) { - const { mutate: downloadByAtflCd } = useDownloadAttachmentByAtflCd(); - const { mutate: downloadByAtflId } = useDownloadAttachmentByAtflId(); - return ( <> {esntlFileList.length > 0 && ( @@ -48,14 +43,12 @@ function AttachmentsViewSection({ esntlFileList, etcFileList }: AttachmentsViewS ) : (
{files.map((file) => ( - downloadByAtflId(file.atflId)} - > - - {file.orgnlFileNm || "다운로드"} - + atflId={file.atflId} + fileName={file.orgnlFileNm || "다운로드"} + className="items-center" + /> ))}
)} @@ -95,13 +88,11 @@ function AttachmentsViewSection({ esntlFileList, etcFileList }: AttachmentsViewS {file.atflCd ? ( - downloadByAtflCd(file.atflCd)} - > - - {file.orgnlFileNm || file.physFileNm || file.atflId} - + ) : ( {file.orgnlFileNm || file.physFileNm || file.atflId} )} diff --git a/apps/as/src/widgets/pbadms-sprt/ui/splmnt-dmnd-form-section.tsx b/apps/as/src/widgets/pbadms-sprt/ui/splmnt-dmnd-form-section.tsx index eea7fb7af..348cfe52e 100644 --- a/apps/as/src/widgets/pbadms-sprt/ui/splmnt-dmnd-form-section.tsx +++ b/apps/as/src/widgets/pbadms-sprt/ui/splmnt-dmnd-form-section.tsx @@ -3,11 +3,9 @@ import { useEffect, useId, useRef, useState } from "react"; import { Controller, useFormContext, useWatch } from "react-hook-form"; -import { Paperclip } from "lucide-react"; - import { dayjs, getDefaultFileKey, useTus } from "@/shared/lib"; import { AttachmentFileField, SectionCollapsible } from "@/shared/ui"; -import { attachService } from "@/entities/attach"; +import { AttachmentDownloadLink, attachService } from "@/entities/attach"; import { Badge, Table, @@ -274,10 +272,10 @@ function SplmntDmndFormSection({ readOnly = false }: SplmntDmndFormSectionProps)
{item.splmntDmndCn || "-"}
{item.splmntDmndAtchFileGroupId ? ( - - - {item.splmntDmndAtchFileNm || "첨부파일"} - + ) : null}
diff --git a/apps/as/src/widgets/pbadms-sprt/ui/supplement-demand-section.tsx b/apps/as/src/widgets/pbadms-sprt/ui/supplement-demand-section.tsx index 1da222fdf..7151323bb 100644 --- a/apps/as/src/widgets/pbadms-sprt/ui/supplement-demand-section.tsx +++ b/apps/as/src/widgets/pbadms-sprt/ui/supplement-demand-section.tsx @@ -1,11 +1,9 @@ "use client"; -import { Paperclip } from "lucide-react"; - import { dayjs } from "@/shared/lib"; import type { SplmntDmndResponseExtension, SplmntDmndSaveBase } from "@/shared/model"; import { SectionCollapsible } from "@/shared/ui"; -import { useDownloadAttachmentByAtflCd } from "@/entities/attach"; +import { AttachmentDownloadLink } from "@/entities/attach"; import { Badge, Table, @@ -23,8 +21,6 @@ interface SupplementDemandSectionProps { } function SupplementDemandSection({ splmntDmndList }: SupplementDemandSectionProps) { - const { mutate: downloadAttachment } = useDownloadAttachmentByAtflCd(); - if (splmntDmndList.length === 0) { return null; } @@ -70,13 +66,10 @@ function SupplementDemandSection({ splmntDmndList }: SupplementDemandSectionProp
{item.splmntDmndCn || "-"}
{item.splmntDmndAtchFileGroupId ? ( - downloadAttachment(item.splmntDmndAtchFileGroupId!)} - > - - {dmndAtchFileNm || "다운로드"} - + ) : null}
@@ -89,13 +82,10 @@ function SupplementDemandSection({ splmntDmndList }: SupplementDemandSectionProp
{item.splmntCn || "-"}
{item.splmntAtchFileGroupId ? ( - downloadAttachment(item.splmntAtchFileGroupId!)} - > - - {cmptnAtchFileNm || "다운로드"} - + ) : null}
From 110d6c689c68c62812be1d33a7e89811b52226ff Mon Sep 17 00:00:00 2001 From: bicochan Date: Fri, 18 Sep 2026 17:33:45 +0900 Subject: [PATCH 11/20] =?UTF-8?q?[as]=20feat:=20UploadedFileChip=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20props=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80(onDownload)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/esntl-atch-file-form-dialog.tsx | 6 +++- .../ui/components/floating-action-buttons.tsx | 2 +- .../components/pwrk-cnsltn-doc-mng-dialog.tsx | 6 +++- .../pages/fnrs-cnsltn/ui/fnrs-form-page.tsx | 36 ++++++++++--------- .../sections/tech-review-opinion-section.tsx | 17 +++++++-- .../src/shared/ui/attachment-file-field.tsx | 2 ++ apps/as/src/shared/ui/uploaded-file-chip.tsx | 29 ++++++++++++--- .../ui/attachments-form-section.tsx | 9 ++++- .../pbadms-sprt/ui/splmnt-dmnd-dialog.tsx | 6 +++- .../ui/splmnt-dmnd-form-section.tsx | 6 +++- 10 files changed, 90 insertions(+), 29 deletions(-) diff --git a/apps/as/src/pages/esntl-atch-file-mng/ui/esntl-atch-file-form-dialog.tsx b/apps/as/src/pages/esntl-atch-file-mng/ui/esntl-atch-file-form-dialog.tsx index 710d6c93d..c7c63ffed 100644 --- a/apps/as/src/pages/esntl-atch-file-mng/ui/esntl-atch-file-form-dialog.tsx +++ b/apps/as/src/pages/esntl-atch-file-mng/ui/esntl-atch-file-form-dialog.tsx @@ -5,7 +5,7 @@ import { useForm } from "react-hook-form"; import { getDefaultFileKey, useTus } from "@/shared/lib"; import { AttachmentFileField } from "@/shared/ui"; -import { attachService } from "@/entities/attach"; +import { attachService, useDownloadAttachmentByAtflId } from "@/entities/attach"; import { CodeSelect } from "@/entities/code"; import type { EsntlAtchFileMng } from "@/entities/esntl"; import { @@ -61,6 +61,7 @@ function EsntlAtchFileFormDialog({ const formId = useId(); const atchFileGroupIdRef = useRef(""); const [uploadedFiles, setUploadedFiles] = useState([]); + const { mutate: downloadByAtflId } = useDownloadAttachmentByAtflId(); const { register, handleSubmit, reset, setValue, watch } = useForm({ defaultValues: { @@ -219,6 +220,9 @@ function EsntlAtchFileFormDialog({ files={uploadedFiles.map((item) => ({ fileKey: item.fileKey, fileName: item.fileName, + onDownload: item.atflId + ? () => downloadByAtflId(item.atflId!) + : undefined, }))} inputId={fileInputId} isUploadingByKey={isUploading} 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 2c32522cc..5d6d58371 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 @@ -597,7 +597,7 @@ function FloatingActionButtons({ )} {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.sncnAprv) && ( - )} diff --git a/apps/as/src/pages/fnrs-cnsltn/ui/components/pwrk-cnsltn-doc-mng-dialog.tsx b/apps/as/src/pages/fnrs-cnsltn/ui/components/pwrk-cnsltn-doc-mng-dialog.tsx index a740f7356..97a7a9e9f 100644 --- a/apps/as/src/pages/fnrs-cnsltn/ui/components/pwrk-cnsltn-doc-mng-dialog.tsx +++ b/apps/as/src/pages/fnrs-cnsltn/ui/components/pwrk-cnsltn-doc-mng-dialog.tsx @@ -8,7 +8,7 @@ import { PanelRightClose, PanelRightOpen } from "lucide-react"; import { getDefaultFileKey, useAlertStore, useTus } from "@/shared/lib"; import { AttachmentFileField } from "@/shared/ui"; -import { attachService, parseFilenameFromResponse } from "@/entities/attach"; +import { attachService, parseFilenameFromResponse, useDownloadAttachmentByAtflId } from "@/entities/attach"; import { pwrkCnsltnDocCrtRsltSaveRequestSchema, pwrkCnsltnDocCrtRsltService, @@ -78,6 +78,7 @@ function PwrkCnsltnDocMngDialog({ const [atchFileGroupId, setAtchFileGroupId] = useState(""); const [uploadedFiles, setUploadedFiles] = useState([]); const [isPjtcoAjmtTableOpen, setIsPjtcoAjmtTableOpen] = useState(false); + const { mutate: downloadByAtflId } = useDownloadAttachmentByAtflId(); const { data: pwrkCnsltnData, @@ -344,6 +345,9 @@ function PwrkCnsltnDocMngDialog({ files={uploadedFiles.map((item) => ({ fileKey: item.fileKey, fileName: item.fileName, + onDownload: item.atflId + ? () => downloadByAtflId(item.atflId!) + : undefined, }))} inputId="pwrk-cnsltn-doc-atch-file-input" isUploadingByKey={isUploading} diff --git a/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-form-page.tsx b/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-form-page.tsx index 632c51e3b..cac88ea86 100644 --- a/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-form-page.tsx +++ b/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-form-page.tsx @@ -332,24 +332,26 @@ function FnrsFormPage({ mode, initialData, createDefaults }: FnrsFormPageProps) )} ) : ( - + <> + {fnrsCnsltnDocNo ? ( + + ) : null} + + )} - {isSplmntPrgrsStts && fnrsCnsltnDocNo ? ( - - ) : null}
diff --git a/apps/as/src/pages/fnrs-cnsltn/ui/sections/tech-review-opinion-section.tsx b/apps/as/src/pages/fnrs-cnsltn/ui/sections/tech-review-opinion-section.tsx index a4c41d527..b00dfce22 100644 --- a/apps/as/src/pages/fnrs-cnsltn/ui/sections/tech-review-opinion-section.tsx +++ b/apps/as/src/pages/fnrs-cnsltn/ui/sections/tech-review-opinion-section.tsx @@ -5,7 +5,11 @@ import { forwardRef, useEffect, useImperativeHandle, useState } from "react"; import { dayjs, getDefaultFileKey, useTus } from "@/shared/lib"; import { AttachmentFileField, SectionCollapsible } from "@/shared/ui"; import { Field, FieldLabel, FieldSet } from "@/shared/ui/field"; -import { AttachmentDownloadLink, attachService } from "@/entities/attach"; +import { + AttachmentDownloadLink, + attachService, + useDownloadAttachmentByAtflId, +} from "@/entities/attach"; import type { FnrsCnsltnRvwOpnnResponseDto } from "@/entities/fnrs-cnsltn"; import { RadioGroup, @@ -79,6 +83,7 @@ const TechReviewOpinionSection = forwardRef< opnrSeComCd: editableReviewStep ?? "", }); const [uploadedFile, setUploadedFile] = useState(null); + const { mutate: downloadByAtflId } = useDownloadAttachmentByAtflId(); useEffect(() => { setFormData((prev) => ({ @@ -243,7 +248,15 @@ const TechReviewOpinionSection = forwardRef< downloadByAtflId(uploadedFile.atflId!) + : undefined, + }, + ] : [] } inputId={`rvw-opnn-${reviewStep}-file-input`} diff --git a/apps/as/src/shared/ui/attachment-file-field.tsx b/apps/as/src/shared/ui/attachment-file-field.tsx index 6867a8323..8eac0dce6 100644 --- a/apps/as/src/shared/ui/attachment-file-field.tsx +++ b/apps/as/src/shared/ui/attachment-file-field.tsx @@ -6,6 +6,7 @@ import { UploadedFileChip } from "./uploaded-file-chip"; interface AttachmentFileFieldItem { fileKey: string; fileName: string; + onDownload?: () => void; } interface AttachmentFileFieldProps { @@ -41,6 +42,7 @@ function AttachmentFileField({ fileName={file.fileName} isUploading={isUploadingByKey[file.fileKey] ?? false} onRemove={onRemove ? () => onRemove(index) : undefined} + onDownload={file.onDownload} /> ))} diff --git a/apps/as/src/shared/ui/uploaded-file-chip.tsx b/apps/as/src/shared/ui/uploaded-file-chip.tsx index 82be5d581..2fb4b437a 100644 --- a/apps/as/src/shared/ui/uploaded-file-chip.tsx +++ b/apps/as/src/shared/ui/uploaded-file-chip.tsx @@ -8,15 +8,36 @@ interface UploadedFileChipProps { fileName: string; isUploading?: boolean; onRemove?: () => void; + onDownload?: () => void; } -function UploadedFileChip({ fileName, isUploading = false, onRemove }: UploadedFileChipProps) { +function UploadedFileChip({ + fileName, + isUploading = false, + onRemove, + onDownload, +}: UploadedFileChipProps) { + const canDownload = Boolean(onDownload) && !isUploading; + return (
- - {fileName} - + {canDownload ? ( + + ) : ( + + {fileName} + + )} {onRemove ? (
diff --git a/apps/as/src/widgets/pbadms-sprt/ui/splmnt-dmnd-dialog.tsx b/apps/as/src/widgets/pbadms-sprt/ui/splmnt-dmnd-dialog.tsx index 2e225a286..8e1facf38 100644 --- a/apps/as/src/widgets/pbadms-sprt/ui/splmnt-dmnd-dialog.tsx +++ b/apps/as/src/widgets/pbadms-sprt/ui/splmnt-dmnd-dialog.tsx @@ -4,7 +4,7 @@ import { useEffect, useId, useState } from "react"; import { getDefaultFileKey, useTus } from "@/shared/lib"; import { AttachmentFileField } from "@/shared/ui"; -import { attachService } from "@/entities/attach"; +import { attachService, useDownloadAttachmentByAtflId } from "@/entities/attach"; import { CodeSelect } from "@/entities/code"; import { Button, @@ -96,6 +96,7 @@ function SplmntDmndDialog({ }: SplmntDmndDialogProps) { const formId = useId(); const [rows, setRows] = useState([createEmptyRow()]); + const { mutate: downloadByAtflId } = useDownloadAttachmentByAtflId(); const { uploadFileAsync, isUploading, uploads } = useTus({ onSuccess: (atflCd, atflId, _file, fileKey) => { @@ -289,6 +290,9 @@ function SplmntDmndDialog({ files={row.uploadedFiles.map((file) => ({ fileKey: file.fileKey, fileName: file.fileName, + onDownload: file.atflId + ? () => downloadByAtflId(file.atflId!) + : undefined, }))} inputId={fileInputId} isUploadingByKey={isUploading} diff --git a/apps/as/src/widgets/pbadms-sprt/ui/splmnt-dmnd-form-section.tsx b/apps/as/src/widgets/pbadms-sprt/ui/splmnt-dmnd-form-section.tsx index 348cfe52e..8fdbec031 100644 --- a/apps/as/src/widgets/pbadms-sprt/ui/splmnt-dmnd-form-section.tsx +++ b/apps/as/src/widgets/pbadms-sprt/ui/splmnt-dmnd-form-section.tsx @@ -5,7 +5,7 @@ import { Controller, useFormContext, useWatch } from "react-hook-form"; import { dayjs, getDefaultFileKey, useTus } from "@/shared/lib"; import { AttachmentFileField, SectionCollapsible } from "@/shared/ui"; -import { AttachmentDownloadLink, attachService } from "@/entities/attach"; +import { AttachmentDownloadLink, attachService, useDownloadAttachmentByAtflId } from "@/entities/attach"; import { Badge, Table, @@ -73,6 +73,7 @@ function SplmntDmndFormSection({ readOnly = false }: SplmntDmndFormSectionProps) const initialFilesMappedRef = useRef(false); const isMountedRef = useRef(true); const atflCdByRowRef = useRef>({}); + const { mutate: downloadByAtflId } = useDownloadAttachmentByAtflId(); const { uploadFileAsync, isUploading, uploads } = useTus({ onSuccess: (atflCd, atflId, _file, fileKey) => { @@ -306,6 +307,9 @@ function SplmntDmndFormSection({ readOnly = false }: SplmntDmndFormSectionProps) files={rowFiles.map((file) => ({ fileKey: file.fileKey, fileName: file.fileName, + onDownload: file.atflId + ? () => downloadByAtflId(file.atflId!) + : undefined, }))} inputId={fileInputId} isUploadingByKey={isUploading} From 50aa549311a3955ee771f6e9bf1067d455e96f7c Mon Sep 17 00:00:00 2001 From: bicochan Date: Mon, 21 Sep 2026 11:02:22 +0900 Subject: [PATCH 12/20] =?UTF-8?q?[as]=20feat:=20=EA=B3=B5=EB=8B=A8=20?= =?UTF-8?q?=EC=8B=A4=EB=AC=B4=ED=98=91=EC=9D=98=EC=84=9C=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=20=EB=B2=84=ED=8A=BC=20=EB=85=B8=EC=B6=9C=20=EC=A1=B0?= =?UTF-8?q?=EA=B1=B4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/fnrs-cnsltn/lib/button-config.ts | 67 ++++++++++++++++++- .../ui/components/floating-action-buttons.tsx | 3 +- .../components/pwrk-cnsltn-doc-mng-dialog.tsx | 12 ++-- 3 files changed, 74 insertions(+), 8 deletions(-) diff --git a/apps/as/src/pages/fnrs-cnsltn/lib/button-config.ts b/apps/as/src/pages/fnrs-cnsltn/lib/button-config.ts index 5adfc3594..22cf9c193 100644 --- a/apps/as/src/pages/fnrs-cnsltn/lib/button-config.ts +++ b/apps/as/src/pages/fnrs-cnsltn/lib/button-config.ts @@ -60,7 +60,20 @@ const ROLE_STATUS_BUTTON_ACTIONS: Record { if (needsAtrzResolve && isRvwLoginUserLoading) return []; diff --git a/apps/as/src/pages/fnrs-cnsltn/ui/components/pwrk-cnsltn-doc-mng-dialog.tsx b/apps/as/src/pages/fnrs-cnsltn/ui/components/pwrk-cnsltn-doc-mng-dialog.tsx index 97a7a9e9f..03363b20d 100644 --- a/apps/as/src/pages/fnrs-cnsltn/ui/components/pwrk-cnsltn-doc-mng-dialog.tsx +++ b/apps/as/src/pages/fnrs-cnsltn/ui/components/pwrk-cnsltn-doc-mng-dialog.tsx @@ -8,7 +8,11 @@ import { PanelRightClose, PanelRightOpen } from "lucide-react"; import { getDefaultFileKey, useAlertStore, useTus } from "@/shared/lib"; import { AttachmentFileField } from "@/shared/ui"; -import { attachService, parseFilenameFromResponse, useDownloadAttachmentByAtflId } from "@/entities/attach"; +import { + attachService, + parseFilenameFromResponse, + useDownloadAttachmentByAtflId, +} from "@/entities/attach"; import { pwrkCnsltnDocCrtRsltSaveRequestSchema, pwrkCnsltnDocCrtRsltService, @@ -43,7 +47,7 @@ const PWRK_ATCH_FILE_KEY_PREFIX = "pwrk-cnsltn-doc::"; const APPROVER_ATRZ_SE_COM_CDS = new Set(["ATRZ03", "ATRZ99"]); -const VIEW_ONLY_PRGRS_STTS_COM_CDS = new Set(["TP", "RA", "RR", "EP", "TA"]); +const VIEW_ONLY_PRGRS_STTS_COM_CDS = new Set(["TP", "RA", "AV", "EV", "RR", "EP", "TA"]); interface PwrkCnsltnDocMngDialogProps { open: boolean; @@ -345,9 +349,7 @@ function PwrkCnsltnDocMngDialog({ files={uploadedFiles.map((item) => ({ fileKey: item.fileKey, fileName: item.fileName, - onDownload: item.atflId - ? () => downloadByAtflId(item.atflId!) - : undefined, + onDownload: item.atflId ? () => downloadByAtflId(item.atflId!) : undefined, }))} inputId="pwrk-cnsltn-doc-atch-file-input" isUploadingByKey={isUploading} From 5fec5d5239aae35e33d443ac20b842ecc6a263b0 Mon Sep 17 00:00:00 2001 From: bicochan Date: Mon, 21 Sep 2026 11:33:59 +0900 Subject: [PATCH 13/20] =?UTF-8?q?[as]=20feat:=20RAG=20=EC=9D=B8=EB=8D=B1?= =?UTF-8?q?=EC=8B=B1=20=EC=83=81=ED=83=9C=EC=9D=BC=20=EB=95=8C=20=EA=B2=80?= =?UTF-8?q?=ED=86=A0=EC=9E=90=20=EC=A7=80=EC=A0=95=20=EB=B2=84=ED=8A=BC=20?= =?UTF-8?q?=EB=B6=84=EA=B8=B0=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/as/src/entities/fnrs-cnsltn/index.ts | 1 + .../model/fnrs-cnsltn-interface.ts | 9 ++++++++ .../pages/fnrs-cnsltn/lib/ai-pending-utils.ts | 16 +++++++++++++- .../ui/components/floating-action-buttons.tsx | 22 ++++++++++--------- .../pages/fnrs-cnsltn/ui/fnrs-view-page.tsx | 11 +++++++--- 5 files changed, 45 insertions(+), 14 deletions(-) diff --git a/apps/as/src/entities/fnrs-cnsltn/index.ts b/apps/as/src/entities/fnrs-cnsltn/index.ts index 31bc2f528..176101dbe 100644 --- a/apps/as/src/entities/fnrs-cnsltn/index.ts +++ b/apps/as/src/entities/fnrs-cnsltn/index.ts @@ -40,6 +40,7 @@ export type { FnrsCnsltnSplmntDmndItem, FnrsCnsltnSplmntDmndResponseDto, FnrsSharItem, + RagIndexingInfoDto, } from "./model/fnrs-cnsltn-interface"; export type { EnvoActnReviewReqDto, 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 8e50d5d79..2165ff49e 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 @@ -151,6 +151,14 @@ export type FnrsCnsltnSplmntDmndResponseDto = FnrsCnsltnSplmntDmndItem & fnrsCnsltnDocNo?: string; }; +/** 백엔드 RagIndexingInfoDto */ +export interface RagIndexingInfoDto { + isInProgress: boolean; + elapsedSeconds?: number; + estimatedRemainingSeconds?: number; + message?: string; +} + /** 백엔드 FnrsCnsltnMngDetResponseDto */ export type FnrsCnsltnMngDetResponseDto = PbadmsMngDetResponseBase< FnrsCnsltnMngResponseDto, @@ -159,6 +167,7 @@ export type FnrsCnsltnMngDetResponseDto = PbadmsMngDetResponseBase< > & { fnrsSharList?: FnrsSharBizCstTreeDto[]; sharAtchFileList?: AtflMngClientResponseDto[]; + ragIndexingInfo?: RagIndexingInfoDto | null; }; /** 백엔드 FnrsCnsltnApplySaveRequestDto */ diff --git a/apps/as/src/pages/fnrs-cnsltn/lib/ai-pending-utils.ts b/apps/as/src/pages/fnrs-cnsltn/lib/ai-pending-utils.ts index 1ac079216..99b1b29ab 100644 --- a/apps/as/src/pages/fnrs-cnsltn/lib/ai-pending-utils.ts +++ b/apps/as/src/pages/fnrs-cnsltn/lib/ai-pending-utils.ts @@ -1,3 +1,5 @@ +import type { RagIndexingInfoDto } from "@/entities/fnrs-cnsltn"; + const AI_PENDING_STATUS_CODES = ["FV", "AC", "AV"] as const; type AiPendingStatusCode = (typeof AI_PENDING_STATUS_CODES)[number]; @@ -17,5 +19,17 @@ function getAiPendingMessage(prgrsSttsComCd: string): string { return AI_PENDING_MESSAGES[prgrsSttsComCd as AiPendingStatusCode]; } -export { AI_PENDING_STATUS_CODES, getAiPendingMessage, isAiPendingStatus }; +function isRagIndexingInProgress( + prgrsSttsComCd: string, + ragIndexingInfo?: RagIndexingInfoDto | null, +): boolean { + return prgrsSttsComCd === "ER" && ragIndexingInfo?.isInProgress === true; +} + +export { + AI_PENDING_STATUS_CODES, + getAiPendingMessage, + isAiPendingStatus, + isRagIndexingInProgress, +}; export type { AiPendingStatusCode }; 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 b3d59f79c..f23e4c521 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 @@ -41,6 +41,7 @@ import { import { SplmntDmndDialog, type SplmntDmndDialogConfirmPayload } from "@/widgets/pbadms-sprt"; import { Button } from "@common/components"; +import { isRagIndexingInProgress } from "../../lib/ai-pending-utils"; import { FNRS_CNSLTN_VIEW_BUTTON_ACTION, type FnrsCnsltnViewButtonAction, @@ -627,16 +628,17 @@ function FloatingActionButtons({ 파일 보완 요청 )} - {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.dsgntRvwr) && ( - - )} + {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.dsgntRvwr) && + !isRagIndexingInProgress(prgrsSttsComCd, data.ragIndexingInfo) && ( + + )} {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.actnCmptn) && ( {!isAiPending && ( <> {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocCrt) && ( - )} @@ -562,85 +654,103 @@ function FloatingActionButtons({ )} {canEdit && ( - )} {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.strg) && ( - )} {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.aply) && ( - )} {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.del) && ( - )} {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.envoSbmsn) && ( - )} {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rjct) && ( - )} {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.sncnAprv) && ( - )} {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwOpnnRply) && ( - )} {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwRply) && ( - )} {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rqstTechRvw) && ( - )} {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rqstActnRvw) && ( - )} {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.fileSplmnt) && ( - )} + {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.fileVrfc) && ( + + )} {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.dsgntRvwr) && !isRagIndexingInProgress(prgrsSttsComCd, data.ragIndexingInfo) && ( )} + {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.costVrfc) && ( + + )} {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.actnCmptn) && ( - )} @@ -648,18 +758,18 @@ function FloatingActionButtons({ )} {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwStrg) && ( - )} {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwCmptn) && ( - )} @@ -667,18 +777,18 @@ function FloatingActionButtons({ )} {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.atrzAprv) && ( - )} {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.atrzRply) && ( - )} @@ -707,14 +817,14 @@ function FloatingActionButtons({ splmntArtclUpCd="SPLMNTARTCL" open={activeDialog === "dmndSplmnt"} onOpenChange={() => setActiveDialog(null)} - isSubmitting={isProcessing} + isSubmitting={isBusy} onConfirm={handleDmndSplmntConfirm} /> setActiveDialog(null)} onConfirm={handleFileSplmntConfirm} /> @@ -748,7 +858,7 @@ function FloatingActionButtons({ setActiveDialog(null)} onConfirm={handleRvwRsltSplmntConfirm} /> @@ -883,6 +993,7 @@ const buttonActionHandlers: Record = rvwOpnnRply: handleTechReview, rqstTechRvw: handleRequestExamine, fileSplmnt: handleDmndSplmnt, + fileVrfc: () => Promise.resolve(), dsgntRvwr: handleDsgntRvwr, pwrkCnsltnDocCrt: () => Promise.resolve(), pwrkCnsltnDocMng: () => Promise.resolve(), @@ -894,6 +1005,7 @@ const buttonActionHandlers: Record = atrzRply: () => Promise.resolve(), actnCmptn: handleActnCmptn, rqstActnRvw: handleRequestActnReview, + costVrfc: () => Promise.resolve(), }; // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/apps/as/src/shared/config/api.ts b/apps/as/src/shared/config/api.ts index a575822f2..c5005396c 100644 --- a/apps/as/src/shared/config/api.ts +++ b/apps/as/src/shared/config/api.ts @@ -26,6 +26,7 @@ export const ENDPOINT = { SEWER_BSC_PLAN: "/as-service/api/v1/sewer-bsc-plans", DASHBOARD: "/as-service/api/v1/dashboard", DCRAG_TO: "/as-service/api/v1/dcrag-to", + AI_AUTO_PRCS_MNG: "/as-service/api/v1/ai-auto-prcs-mng", PWRK_CNSLTN_MNG: "/as-service/api/v1/pwrk-cnsltn-mng", PWRK_CNSLTN_DOC_CRT_RSLT: "/as-service/api/v1/pwrk-cnsltn-doc-crt-rslt", PWRK_CNSLTN_DOC_PJTCO_AJMT_MNG: "/as-service/api/v1/pwrk-cnsltn-doc-pjtco-ajmt-mng", From 2c355525df7680317220f2cb9a14490a4f380aa6 Mon Sep 17 00:00:00 2001 From: 100JM Date: Mon, 21 Sep 2026 13:55:37 +0900 Subject: [PATCH 15/20] =?UTF-8?q?[il]=20-=20DB=20=ED=91=9C=EC=A4=80?= =?UTF-8?q?=ED=99=94=EB=A1=9C=20=EC=9D=B8=ED=95=9C=20=EC=86=8C=EC=8A=A4=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/cs/src/entities/link/model/link-interface.ts | 4 ++-- apps/cs/src/pages/linkLog/model/table-columns.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/cs/src/entities/link/model/link-interface.ts b/apps/cs/src/entities/link/model/link-interface.ts index 7640e3b8f..6cd1ba560 100644 --- a/apps/cs/src/entities/link/model/link-interface.ts +++ b/apps/cs/src/entities/link/model/link-interface.ts @@ -31,7 +31,7 @@ export interface LinkLog { err_cn: string; link_err_nm: string; log_crt_dt: string; - link_exec_step: string; + link_excn_stp_nm: string; } export interface LinkInfo extends LinkFormData { @@ -114,7 +114,7 @@ export const linkFormSchema = z.object({ link_db_nm: z.string().max(10).nullable().optional(), link_api_no: z.string().max(100, { message: '연계 KEY는 100자 이하로 입력해 주세요.' }).nonempty({ message: '연계 KEY는 필수입니다.' }), link_cntn_nm: z.string().max(20).nullable().optional(), - link_cntn_tkn_no: z.string().max(128).nullable().optional(), + link_cntn_tkn_no: z.string().max(25, { message: '연계 접속 토큰은 25자 이하로 입력해 주세요.' }).nullable().optional(), srvc_usg_nm: z.string().max(40).nullable().optional(), last_link_rslt_nm: z.string().max(4).nullable().optional(), last_link_excn_dt: z.string().max(40).nullable().optional(), diff --git a/apps/cs/src/pages/linkLog/model/table-columns.tsx b/apps/cs/src/pages/linkLog/model/table-columns.tsx index b5b2c7ff3..d5180d524 100644 --- a/apps/cs/src/pages/linkLog/model/table-columns.tsx +++ b/apps/cs/src/pages/linkLog/model/table-columns.tsx @@ -17,8 +17,8 @@ const columns = [ id: 'link_nm', header: '연계 명', }), - columnHelper.accessor('link_exec_step', { - id: 'link_exec_step', + columnHelper.accessor('link_excn_stp_nm', { + id: 'link_excn_stp_nm', header: '연계실행단계', cell: (info) => (info.getValue() ? info.getValue() : '-'), }), From 342db06685f47ddba4331a418d3e8d8473b07ee6 Mon Sep 17 00:00:00 2001 From: bicochan Date: Mon, 21 Sep 2026 15:18:42 +0900 Subject: [PATCH 16/20] =?UTF-8?q?[as]=20refactor:=20=ED=96=89=EC=A0=95?= =?UTF-8?q?=EC=A7=80=EC=9B=90=20=EB=AC=B8=EC=84=9C=20=EC=A0=80=EC=9E=A5=20?= =?UTF-8?q?payload=20=EC=8A=A4=ED=82=A4=EB=A7=88=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/design-cnstn-mng-service.ts | 4 +- .../api/design-cnstn-rvw-opnn-service.ts | 2 +- .../src/entities/design-cnstn/api/queries.ts | 4 +- apps/as/src/entities/design-cnstn/index.ts | 22 ++- .../design-cnstn-apply-payload-schema.ts | 74 +++++++ .../model/design-cnstn-mng-interface.ts | 62 +----- .../model/design-cnstn-rvw-opnn-interface.ts | 13 +- .../fnrs-cnsltn/api/fnrs-cnsltn-service.ts | 6 +- .../src/entities/fnrs-cnsltn/api/queries.ts | 4 +- apps/as/src/entities/fnrs-cnsltn/index.ts | 31 ++- .../model/fnrs-cnsltn-apply-payload-schema.ts | 120 ++++++++++++ .../model/fnrs-cnsltn-interface.ts | 81 +------- .../instl-sncn/api/instl-sncn-service.ts | 6 +- .../as/src/entities/instl-sncn/api/queries.ts | 4 +- apps/as/src/entities/instl-sncn/index.ts | 28 ++- .../model/instl-sncn-apply-payload-schema.ts | 108 +++++++++++ .../instl-sncn/model/instl-sncn-interface.ts | 183 ++---------------- .../sewer-bsc-plan-apply-payload-schema.ts | 2 +- .../lib/design-cnstn-regist-schema.ts | 28 +-- .../design-cnstn/lib/form-data-mapper.ts | 32 ++- .../design-cnstn/lib/save-payload-utils.ts | 9 +- .../design-cnstn/ui/design-form-page.tsx | 34 ++-- .../lib/fnrs-cnsltn-regist-schema.ts | 60 ++---- .../pages/fnrs-cnsltn/lib/form-data-mapper.ts | 70 +++++-- .../fnrs-cnsltn/lib/save-payload-utils.ts | 31 +-- .../pages/fnrs-cnsltn/ui/fnrs-form-page.tsx | 63 ++---- .../pages/instl-sncn/lib/form-data-mapper.ts | 54 ++++-- .../lib/instl-sncn-regist-schema.ts | 54 ++---- .../instl-sncn/lib/save-payload-utils.ts | 14 +- .../pages/instl-sncn/ui/instl-form-page.tsx | 46 +---- .../pages/sewer-bsc-plan/lib/payload-utils.ts | 13 +- .../lib/sewer-bsc-plan-regist-schema.ts | 2 +- .../pbadms-sprt/lib/checklist-form-utils.ts | 2 +- .../pbadms-sprt/ui/checklist-form-section.tsx | 4 +- 34 files changed, 642 insertions(+), 628 deletions(-) create mode 100644 apps/as/src/entities/design-cnstn/model/design-cnstn-apply-payload-schema.ts create mode 100644 apps/as/src/entities/fnrs-cnsltn/model/fnrs-cnsltn-apply-payload-schema.ts create mode 100644 apps/as/src/entities/instl-sncn/model/instl-sncn-apply-payload-schema.ts diff --git a/apps/as/src/entities/design-cnstn/api/design-cnstn-mng-service.ts b/apps/as/src/entities/design-cnstn/api/design-cnstn-mng-service.ts index 3fc3e52ae..39ff512a9 100644 --- a/apps/as/src/entities/design-cnstn/api/design-cnstn-mng-service.ts +++ b/apps/as/src/entities/design-cnstn/api/design-cnstn-mng-service.ts @@ -4,9 +4,11 @@ import type { PageResponse } from "@/shared/model"; import type { DesignCnstnApplySaveRequestDto, + DesignCnstnMngSaveRequestDto, +} from "../model/design-cnstn-apply-payload-schema"; +import type { DesignCnstnMngDetResponseDto, DesignCnstnMngResponseDto, - DesignCnstnMngSaveRequestDto, DesignCnstnMngSearchDto, DesignCnstnMngService, DesignCnstnMngUpdateRequestDto, diff --git a/apps/as/src/entities/design-cnstn/api/design-cnstn-rvw-opnn-service.ts b/apps/as/src/entities/design-cnstn/api/design-cnstn-rvw-opnn-service.ts index 514a0423f..ddfc3d885 100644 --- a/apps/as/src/entities/design-cnstn/api/design-cnstn-rvw-opnn-service.ts +++ b/apps/as/src/entities/design-cnstn/api/design-cnstn-rvw-opnn-service.ts @@ -2,10 +2,10 @@ import { client } from "@/shared/api"; import { ENDPOINT } from "@/shared/config"; import type { PageResponse } from "@/shared/model"; +import type { DesignCnstnRvwOpnnSaveRequestDto } from "../model/design-cnstn-apply-payload-schema"; import type { DesignCnstnRvwOpnnId, DesignCnstnRvwOpnnResponseDto, - DesignCnstnRvwOpnnSaveRequestDto, DesignCnstnRvwOpnnSearchDto, DesignCnstnRvwOpnnService, DesignCnstnRvwOpnnUpdateRequestDto, diff --git a/apps/as/src/entities/design-cnstn/api/queries.ts b/apps/as/src/entities/design-cnstn/api/queries.ts index c98a5ad15..7a04eb8d8 100644 --- a/apps/as/src/entities/design-cnstn/api/queries.ts +++ b/apps/as/src/entities/design-cnstn/api/queries.ts @@ -18,11 +18,13 @@ import type { import type { DesignCnstnApplySaveRequestDto, DesignCnstnMngSaveRequestDto, + DesignCnstnRvwOpnnSaveRequestDto, +} from "../model/design-cnstn-apply-payload-schema"; +import type { DesignCnstnMngSearchDto, DesignCnstnMngUpdateRequestDto, } from "../model/design-cnstn-mng-interface"; import type { - DesignCnstnRvwOpnnSaveRequestDto, DesignCnstnRvwOpnnSearchDto, DesignCnstnRvwOpnnUpdateRequestDto, } from "../model/design-cnstn-rvw-opnn-interface"; diff --git a/apps/as/src/entities/design-cnstn/index.ts b/apps/as/src/entities/design-cnstn/index.ts index cad262c32..b09702d6e 100644 --- a/apps/as/src/entities/design-cnstn/index.ts +++ b/apps/as/src/entities/design-cnstn/index.ts @@ -63,23 +63,33 @@ export type { } from "./model/design-cnstn-esntl-atch-file-interface"; export type { AtflMngClientResponseDto, - BizCstItem, BizCstTreeDto, BizSclTreeDto, - BzScaleItem, - DesignCnstnApplySaveRequestDto, DesignCnstnMngDetResponseDto, DesignCnstnMngResponseDto, - DesignCnstnMngSaveRequestDto, DesignCnstnMngSearchDto, DesignCnstnMngService, DesignCnstnMngUpdateRequestDto, DesignCnstnRvwOpnnResponseDto, - DesignCnstnRvwOpnnSaveRequestDto, ElaprDocPrgrsClientResponseDto, - EsntlAtchFileItem, EsntlAtchFileMngTreeResponseDto, } from "./model/design-cnstn-mng-interface"; +export type { + BizCstItem, + BzScaleItem, + DesignCnstnApplySaveRequestDto, + DesignCnstnMngSaveRequestDto, + DesignCnstnRvwOpnnSaveRequestDto, + EsntlAtchFileItem, +} from "./model/design-cnstn-apply-payload-schema"; +export { + designCnstnApplySaveSchema, + designCnstnBizCstItemSchema, + designCnstnBzScaleItemSchema, + designCnstnEsntlAtchFileItemSchema, + designCnstnMngSaveSchema, + designCnstnRvwOpnnSaveSchema, +} from "./model/design-cnstn-apply-payload-schema"; export type { DesignCnstnRvwOpnnId, DesignCnstnRvwOpnnSearchDto, diff --git a/apps/as/src/entities/design-cnstn/model/design-cnstn-apply-payload-schema.ts b/apps/as/src/entities/design-cnstn/model/design-cnstn-apply-payload-schema.ts new file mode 100644 index 000000000..5b6c76b10 --- /dev/null +++ b/apps/as/src/entities/design-cnstn/model/design-cnstn-apply-payload-schema.ts @@ -0,0 +1,74 @@ +import { z } from "zod"; + +/** 백엔드 DesignCnstnMngSaveRequestDto */ +export const designCnstnMngSaveSchema = z.object({ + designCnstnDocNo: z.string().optional(), + admdstCd: z.string().optional(), + envoSeComCd: z.string().optional(), + taskSeComCd: z.string().optional(), + bizNm: z.string().optional(), + bizBgngYr: z.string().optional(), + bizEndYr: z.string().optional(), + bizCn: z.string().optional(), + aplcntNm: z.string().optional(), + aplcntMblTelno: z.string().optional(), + aplcntOgdpNm: z.string().optional(), + aplcntEmlAddr: z.string().optional(), + dsgnrNm: z.string().optional(), + dsgnrTelno: z.string().optional(), + dsgnrOgdpNm: z.string().optional(), + dsgnrEmlAddr: z.string().optional(), + atchFileGroupId: z.string().optional(), + prgrsSttsComCd: z.string().optional(), +}); + +/** 백엔드 DesignCnstnApplySaveRequestDto.BzScaleItem */ +export const designCnstnBzScaleItemSchema = z.object({ + cnstpSeCd: z.string().optional(), + bscPl: z.number().optional(), + budgetReflct: z.number().optional(), + thtiDsgn: z.number().optional(), +}); + +/** 백엔드 DesignCnstnApplySaveRequestDto.BizCstItem */ +export const designCnstnBizCstItemSchema = z.object({ + acntgSeCd: z.string().optional(), + bscPlanAmt: z.number().optional(), + bgtRfltAmt: z.number().optional(), + tstmDesignAmt: z.number().optional(), +}); + +/** 백엔드 DesignCnstnApplySaveRequestDto.EsntlAtchFileItem */ +export const designCnstnEsntlAtchFileItemSchema = z.object({ + esntlAtchFileId: z.string().optional(), + atchFileGroupId: z.string().optional(), +}); + +/** 백엔드 DesignCnstnRvwOpnnSaveRequestDto */ +export const designCnstnRvwOpnnSaveSchema = z.object({ + designCnstnDocNo: z.string(), + rvwOpnnSn: z.number().optional(), + opnrSeComCd: z.string().optional(), + opnrNm: z.string().optional(), + rvwRsltCn: z.string().optional(), + rvwRsltAnmlyYn: z.string().optional(), + atchFileGroupId: z.string().optional(), +}); + +/** 백엔드 DesignCnstnApplySaveRequestDto */ +export const designCnstnApplySaveSchema = z.object({ + techReViewSaveCd: z.string().optional(), + rvwStpCd: z.string().optional(), + designCnstnMng: designCnstnMngSaveSchema, + bzScaleList: z.array(designCnstnBzScaleItemSchema).optional(), + bizCstList: z.array(designCnstnBizCstItemSchema).optional(), + esntlAtchFileList: z.array(designCnstnEsntlAtchFileItemSchema).optional(), + rvwOpnnList: z.array(designCnstnRvwOpnnSaveSchema).optional(), +}); + +export type DesignCnstnMngSaveRequestDto = z.infer; +export type BzScaleItem = z.infer; +export type BizCstItem = z.infer; +export type EsntlAtchFileItem = z.infer; +export type DesignCnstnRvwOpnnSaveRequestDto = z.infer; +export type DesignCnstnApplySaveRequestDto = z.infer; diff --git a/apps/as/src/entities/design-cnstn/model/design-cnstn-mng-interface.ts b/apps/as/src/entities/design-cnstn/model/design-cnstn-mng-interface.ts index 1ee2be991..bc4949eb3 100644 --- a/apps/as/src/entities/design-cnstn/model/design-cnstn-mng-interface.ts +++ b/apps/as/src/entities/design-cnstn/model/design-cnstn-mng-interface.ts @@ -1,22 +1,12 @@ -import type { - BizCstSaveBase, - BzScaleSaveBase, - EsntlAtchFileSaveBase, - PageableParams, - PageResponse, - PbadmsApplySaveHeader, - PbadmsMngDetResponseBase, -} from "@/shared/model"; +import type { PageableParams, PageResponse, PbadmsMngDetResponseBase } from "@/shared/model"; import type { - DesignCnstnRvwOpnnResponseDto, - DesignCnstnRvwOpnnSaveRequestDto, -} from "./design-cnstn-rvw-opnn-interface"; + DesignCnstnApplySaveRequestDto, + DesignCnstnMngSaveRequestDto, +} from "./design-cnstn-apply-payload-schema"; +import type { DesignCnstnRvwOpnnResponseDto } from "./design-cnstn-rvw-opnn-interface"; -export type { - DesignCnstnRvwOpnnResponseDto, - DesignCnstnRvwOpnnSaveRequestDto, -} from "./design-cnstn-rvw-opnn-interface"; +export type { DesignCnstnRvwOpnnResponseDto } from "./design-cnstn-rvw-opnn-interface"; export type { AtflMngClientResponseDto, BizCstTreeDto, @@ -25,28 +15,6 @@ export type { EsntlAtchFileMngTreeResponseDto, } from "@/shared/model"; -/** 백엔드 DesignCnstnMngSaveRequestDto */ -export interface DesignCnstnMngSaveRequestDto { - designCnstnDocNo?: string; - admdstCd?: string; - envoSeComCd?: string; - taskSeComCd?: string; - bizNm?: string; - bizBgngYr?: string; - bizEndYr?: string; - bizCn?: string; - aplcntNm?: string; - aplcntMblTelno?: string; - aplcntOgdpNm?: string; - aplcntEmlAddr?: string; - dsgnrNm?: string; - dsgnrTelno?: string; - dsgnrOgdpNm?: string; - dsgnrEmlAddr?: string; - atchFileGroupId?: string; - prgrsSttsComCd?: string; -} - /** 백엔드 DesignCnstnMngUpdateRequestDto */ export type DesignCnstnMngUpdateRequestDto = Omit; @@ -88,30 +56,12 @@ interface DesignCnstnMngResponseExtension { export type DesignCnstnMngResponseDto = Omit & DesignCnstnMngResponseExtension; -/** 백엔드 DesignCnstnApplySaveRequestDto.BzScaleItem */ -export type BzScaleItem = BzScaleSaveBase; - -/** 백엔드 DesignCnstnApplySaveRequestDto.BizCstItem */ -export type BizCstItem = BizCstSaveBase; - -/** 백엔드 DesignCnstnApplySaveRequestDto.EsntlAtchFileItem */ -export type EsntlAtchFileItem = EsntlAtchFileSaveBase; - /** 백엔드 DesignCnstnMngDetResponseDto */ export type DesignCnstnMngDetResponseDto = PbadmsMngDetResponseBase< DesignCnstnMngResponseDto, DesignCnstnRvwOpnnResponseDto >; -/** 백엔드 DesignCnstnApplySaveRequestDto */ -export interface DesignCnstnApplySaveRequestDto extends PbadmsApplySaveHeader { - designCnstnMng: DesignCnstnMngSaveRequestDto; - bzScaleList?: BzScaleItem[]; - bizCstList?: BizCstItem[]; - esntlAtchFileList?: EsntlAtchFileItem[]; - rvwOpnnList?: DesignCnstnRvwOpnnSaveRequestDto[]; -} - /** Controller public 메서드명·시그니처와 동일 */ export interface DesignCnstnMngService { findPage(searchDto: DesignCnstnMngSearchDto): Promise>; diff --git a/apps/as/src/entities/design-cnstn/model/design-cnstn-rvw-opnn-interface.ts b/apps/as/src/entities/design-cnstn/model/design-cnstn-rvw-opnn-interface.ts index 8b9841ee6..56cc7b94c 100644 --- a/apps/as/src/entities/design-cnstn/model/design-cnstn-rvw-opnn-interface.ts +++ b/apps/as/src/entities/design-cnstn/model/design-cnstn-rvw-opnn-interface.ts @@ -1,22 +1,13 @@ import type { PageableParams, PageResponse, RvwOpnnResponseExtension } from "@/shared/model"; +import type { DesignCnstnRvwOpnnSaveRequestDto } from "./design-cnstn-apply-payload-schema"; + /** 백엔드 DesignCnstnRvwOpnnId */ export interface DesignCnstnRvwOpnnId { designCnstnMng: string; rvwOpnnSn: number; } -/** 백엔드 DesignCnstnRvwOpnnSaveRequestDto */ -export interface DesignCnstnRvwOpnnSaveRequestDto { - designCnstnDocNo: string; - rvwOpnnSn?: number; - opnrSeComCd?: string; - opnrNm?: string; - rvwRsltCn?: string; - rvwRsltAnmlyYn?: string; - atchFileGroupId?: string; -} - /** 백엔드 DesignCnstnRvwOpnnUpdateRequestDto */ export interface DesignCnstnRvwOpnnUpdateRequestDto { opnrSeComCd?: string; 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 b48e5a059..ffac5eb4a 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 @@ -3,12 +3,14 @@ import { ENDPOINT } from "@/shared/config"; import type { PageResponse } from "@/shared/model"; import type { - DocPrgrsUpdateRequestDto, FnrsCnsltnApplySaveRequestDto, + FnrsCnsltnMngSaveRequestDto, +} from "../model/fnrs-cnsltn-apply-payload-schema"; +import type { + DocPrgrsUpdateRequestDto, FnrsCnsltnFileVrfcRsltResponseDto, FnrsCnsltnMngDetResponseDto, FnrsCnsltnMngResponseDto, - FnrsCnsltnMngSaveRequestDto, FnrsCnsltnMngSearchDto, FnrsCnsltnMngService, FnrsCnsltnMngUpdateRequestDto, diff --git a/apps/as/src/entities/fnrs-cnsltn/api/queries.ts b/apps/as/src/entities/fnrs-cnsltn/api/queries.ts index 357aa58c0..e136bd59f 100644 --- a/apps/as/src/entities/fnrs-cnsltn/api/queries.ts +++ b/apps/as/src/entities/fnrs-cnsltn/api/queries.ts @@ -1,9 +1,11 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import type { - DocPrgrsUpdateRequestDto, FnrsCnsltnApplySaveRequestDto, FnrsCnsltnMngSaveRequestDto, +} from "../model/fnrs-cnsltn-apply-payload-schema"; +import type { + DocPrgrsUpdateRequestDto, FnrsCnsltnMngSearchDto, FnrsCnsltnMngUpdateRequestDto, } from "../model/fnrs-cnsltn-interface"; diff --git a/apps/as/src/entities/fnrs-cnsltn/index.ts b/apps/as/src/entities/fnrs-cnsltn/index.ts index 176101dbe..1fba74291 100644 --- a/apps/as/src/entities/fnrs-cnsltn/index.ts +++ b/apps/as/src/entities/fnrs-cnsltn/index.ts @@ -17,31 +17,44 @@ export { } from "./api/queries"; export type { AtflMngClientResponseDto, - BizCstItem, BizCstTreeDto, BizSclTreeDto, - BzScaleItem, - CklstResultItem, CklstRvwRsltTreeDto, DocPrgrsUpdateRequestDto, ElaprDocPrgrsClientResponseDto, - EsntlAtchFileItem, EsntlAtchFileMngTreeResponseDto, - FnrsCnsltnApplySaveRequestDto, FnrsCnsltnFileVrfcRsltResponseDto, FnrsCnsltnMngDetResponseDto, FnrsCnsltnMngResponseDto, - FnrsCnsltnMngSaveRequestDto, FnrsCnsltnMngSearchDto, FnrsCnsltnMngService, FnrsCnsltnMngUpdateRequestDto, FnrsCnsltnRvwOpnnResponseDto, - FnrsCnsltnRvwOpnnSaveRequestDto, - FnrsCnsltnSplmntDmndItem, FnrsCnsltnSplmntDmndResponseDto, - FnrsSharItem, RagIndexingInfoDto, } from "./model/fnrs-cnsltn-interface"; +export type { + BizCstItem, + BzScaleItem, + CklstResultItem, + EsntlAtchFileItem, + FnrsCnsltnApplySaveRequestDto, + FnrsCnsltnMngSaveRequestDto, + FnrsCnsltnRvwOpnnSaveRequestDto, + FnrsCnsltnSplmntDmndItem, + FnrsSharItem, +} from "./model/fnrs-cnsltn-apply-payload-schema"; +export { + fnrsCnsltnApplySaveSchema, + fnrsCnsltnBizCstItemSchema, + fnrsCnsltnBzScaleItemSchema, + fnrsCnsltnCklstResultItemSchema, + fnrsCnsltnEsntlAtchFileItemSchema, + fnrsCnsltnMngSaveSchema, + fnrsCnsltnRvwOpnnSaveSchema, + fnrsCnsltnSplmntDmndItemSchema, + fnrsSharItemSchema, +} from "./model/fnrs-cnsltn-apply-payload-schema"; export type { EnvoActnReviewReqDto, FnrsExamineRequestDto, diff --git a/apps/as/src/entities/fnrs-cnsltn/model/fnrs-cnsltn-apply-payload-schema.ts b/apps/as/src/entities/fnrs-cnsltn/model/fnrs-cnsltn-apply-payload-schema.ts new file mode 100644 index 000000000..709ae9012 --- /dev/null +++ b/apps/as/src/entities/fnrs-cnsltn/model/fnrs-cnsltn-apply-payload-schema.ts @@ -0,0 +1,120 @@ +import { z } from "zod"; + +/** 백엔드 FnrsCnsltnMngSaveRequestDto */ +export const fnrsCnsltnMngSaveSchema = z.object({ + fnrsCnsltnDocNo: z.string().optional(), + admdstCd: z.string().optional(), + envoSeComCd: z.string().optional(), + taskSeComCd: z.string().optional(), + cfmtnBgtBizNo: z.string().optional(), + bgtAplyYr: z.string().optional(), + bizNm: z.string().optional(), + bizBgngYr: z.string().optional(), + bizEndYr: z.string().optional(), + bizCn: z.string().optional(), + aplcntNm: z.string().optional(), + aplcntMblTelno: z.string().optional(), + aplcntOgdpNm: z.string().optional(), + aplcntEmlAddr: z.string().optional(), + dsgnrNm: z.string().optional(), + dsgnrTelno: z.string().optional(), + dsgnrOgdpNm: z.string().optional(), + dsgnrEmlAddr: z.string().optional(), + atchFileGroupId: z.string().optional(), + sharAtchFileGroupId: z.string().optional(), + prgrsSttsComCd: z.string().optional(), + rtlztnFcltSeComCd: z.string().optional(), + rtlztnUsgSeComCd: z.string().optional(), +}); + +/** 백엔드 FnrsCnsltnApplySaveRequestDto.BzScaleItem */ +export const fnrsCnsltnBzScaleItemSchema = z.object({ + cnstpSeCd: z.string().optional(), + bscPl: z.number().optional(), + budgetReflct: z.number().optional(), + thtiDsgn: z.number().optional(), +}); + +/** 백엔드 FnrsCnsltnApplySaveRequestDto.BizCstItem */ +export const fnrsCnsltnBizCstItemSchema = z.object({ + acntgSeCd: z.string().optional(), + bscPlanAmt: z.number().optional(), + bgtRfltAmt: z.number().optional(), + tstmDesignAmt: z.number().optional(), +}); + +/** 백엔드 FnrsCnsltnApplySaveRequestDto.CklstResultItem */ +export const fnrsCnsltnCklstResultItemSchema = z.object({ + cklstRvwSn: z.number().optional(), + cklstArtclSn: z.number().optional(), + cklstSn: z.number().optional(), + rvwStpComCd: z.string().nullish(), + selected: z.enum(["Y", "N"]).nullish(), + picRvwCn: z.string().nullish(), +}); + +/** 백엔드 FnrsCnsltnApplySaveRequestDto.EsntlAtchFileItem */ +export const fnrsCnsltnEsntlAtchFileItemSchema = z.object({ + esntlAtchFileId: z.string().optional(), + atchFileGroupId: z.string().optional(), +}); + +/** 백엔드 FnrsCnsltnApplySaveRequestDto.FnrsCnsltnSplmntDmndItem */ +export const fnrsCnsltnSplmntDmndItemSchema = z.object({ + splmntDmndSn: z.number().nullish(), + splmntArtclComCd: z.string().nullish(), + splmntDmndCn: z.string().optional(), + splmntDmndDt: z.string().optional(), + splmntDmndAtchFileGroupId: z.string().optional(), + splmntCn: z.string().optional(), + splmntPicNm: z.string().optional(), + splmntCmptnDt: z.string().optional(), + splmntAtchFileGroupId: z.string().optional(), + cmptnYn: z.string().optional(), +}); + +/** 백엔드 FnrsCnsltnRvwOpnnSaveRequestDto */ +export const fnrsCnsltnRvwOpnnSaveSchema = z.object({ + fnrsCnsltnDocNo: z.string(), + rvwOpnnSn: z.number().optional(), + opnrSeComCd: z.string().optional(), + opnrNm: z.string().optional(), + rvwRsltCn: z.string().optional(), + rvwRsltAnmlyYn: z.string().optional(), + atchFileGroupId: z.string().optional(), +}); + +/** 백엔드 FnrsCnsltnApplySaveRequestDto.FnrsSharItem */ +export const fnrsSharItemSchema = z.object({ + fnrsSharSeCd: z.string().optional(), + exstnAmt: z.number().optional(), + chgRqtAmt: z.number().optional(), + ajmtAmt: z.number().optional(), + rmrkCn: z.string().optional(), + envoRmrkCn: z.string().optional(), +}); + +/** 백엔드 FnrsCnsltnApplySaveRequestDto */ +export const fnrsCnsltnApplySaveSchema = z.object({ + techReViewSaveCd: z.string().optional(), + rvwStpCd: z.string().optional(), + fnrsCnsltnMng: fnrsCnsltnMngSaveSchema, + bzScaleList: z.array(fnrsCnsltnBzScaleItemSchema).optional(), + bizCstList: z.array(fnrsCnsltnBizCstItemSchema).optional(), + cklstResultList: z.array(fnrsCnsltnCklstResultItemSchema).optional(), + cklstResultMap: z.record(z.array(fnrsCnsltnCklstResultItemSchema)).optional(), + esntlAtchFileList: z.array(fnrsCnsltnEsntlAtchFileItemSchema).optional(), + rvwOpnnList: z.array(fnrsCnsltnRvwOpnnSaveSchema).optional(), + splmntDmndList: z.array(fnrsCnsltnSplmntDmndItemSchema).optional(), + fnrsSharList: z.array(fnrsSharItemSchema).optional(), +}); + +export type FnrsCnsltnMngSaveRequestDto = z.infer; +export type BzScaleItem = z.infer; +export type BizCstItem = z.infer; +export type CklstResultItem = z.infer; +export type EsntlAtchFileItem = z.infer; +export type FnrsCnsltnSplmntDmndItem = z.infer; +export type FnrsCnsltnRvwOpnnSaveRequestDto = z.infer; +export type FnrsSharItem = z.infer; +export type FnrsCnsltnApplySaveRequestDto = z.infer; 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 2165ff49e..07d3983e9 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 @@ -1,21 +1,20 @@ import type { AtflMngClientResponseDto, - BizCstSaveBase, - BzScaleSaveBase, - CklstResultSaveBase, DocPrgrsUpdateRequestDto, - EsntlAtchFileSaveBase, PageableParams, PageResponse, - PbadmsApplySaveHeader, PbadmsMngDetResponseBase, RvwOpnnResponseExtension, - RvwOpnnSaveBase, SplmntDmndResponseExtension, - SplmntDmndSaveBase, } from "@/shared/model"; import type { FnrsSharBizCstTreeDto } from "@/entities/fnrs-shar-se"; +import type { + FnrsCnsltnApplySaveRequestDto, + FnrsCnsltnMngSaveRequestDto, + FnrsCnsltnRvwOpnnSaveRequestDto, + FnrsCnsltnSplmntDmndItem, +} from "./fnrs-cnsltn-apply-payload-schema"; import type { EnvoActnReviewReqDto, FnrsExamineRequestDto, @@ -31,33 +30,6 @@ export type { EsntlAtchFileMngTreeResponseDto, } from "@/shared/model"; -/** 백엔드 FnrsCnsltnMngSaveRequestDto */ -export interface FnrsCnsltnMngSaveRequestDto { - fnrsCnsltnDocNo?: string; - admdstCd?: string; - envoSeComCd?: string; - taskSeComCd?: string; - cfmtnBgtBizNo?: string; - bgtAplyYr?: string; - bizNm?: string; - bizBgngYr?: string; - bizEndYr?: string; - bizCn?: string; - aplcntNm?: string; - aplcntMblTelno?: string; - aplcntOgdpNm?: string; - aplcntEmlAddr?: string; - dsgnrNm?: string; - dsgnrTelno?: string; - dsgnrOgdpNm?: string; - dsgnrEmlAddr?: string; - atchFileGroupId?: string; - sharAtchFileGroupId?: string; - prgrsSttsComCd?: string; - rtlztnFcltSeComCd?: string; - rtlztnUsgSeComCd?: string; -} - /** 백엔드 FnrsCnsltnMngUpdateRequestDto */ export type FnrsCnsltnMngUpdateRequestDto = Omit; @@ -110,34 +82,6 @@ interface FnrsCnsltnMngResponseExtension { export type FnrsCnsltnMngResponseDto = Omit & FnrsCnsltnMngResponseExtension; -export type BzScaleItem = BzScaleSaveBase; - -export type BizCstItem = BizCstSaveBase; - -export interface CklstResultItem extends CklstResultSaveBase { - selected?: string; -} - -export type EsntlAtchFileItem = EsntlAtchFileSaveBase; - -export type FnrsCnsltnSplmntDmndItem = SplmntDmndSaveBase; - -/** 백엔드 FnrsCnsltnApplySaveRequestDto.FnrsSharItem */ -export interface FnrsSharItem { - fnrsSharSeCd?: string; - exstnAmt?: number; - chgRqtAmt?: number; - ajmtAmt?: number; - rmrkCn?: string; - envoRmrkCn?: string; -} - -/** 백엔드 FnrsCnsltnRvwOpnnSaveRequestDto */ -export interface FnrsCnsltnRvwOpnnSaveRequestDto extends RvwOpnnSaveBase { - fnrsCnsltnDocNo: string; - rvwOpnnSn: number; -} - /** 백엔드 FnrsCnsltnRvwOpnnResponseDto */ export type FnrsCnsltnRvwOpnnResponseDto = Partial< Pick @@ -170,19 +114,6 @@ export type FnrsCnsltnMngDetResponseDto = PbadmsMngDetResponseBase< ragIndexingInfo?: RagIndexingInfoDto | null; }; -/** 백엔드 FnrsCnsltnApplySaveRequestDto */ -export interface FnrsCnsltnApplySaveRequestDto extends PbadmsApplySaveHeader { - fnrsCnsltnMng: FnrsCnsltnMngSaveRequestDto; - bzScaleList?: BzScaleItem[]; - bizCstList?: BizCstItem[]; - cklstResultList?: CklstResultItem[]; - cklstResultMap?: Record; - esntlAtchFileList?: EsntlAtchFileItem[]; - rvwOpnnList?: FnrsCnsltnRvwOpnnSaveRequestDto[]; - splmntDmndList?: FnrsCnsltnSplmntDmndItem[]; - fnrsSharList?: FnrsSharItem[]; -} - /** 백엔드 FnrsCnsltnFileVrfcRsltResponseDto */ export interface FnrsCnsltnFileVrfcRsltResponseDto { fileSeComCd?: string; diff --git a/apps/as/src/entities/instl-sncn/api/instl-sncn-service.ts b/apps/as/src/entities/instl-sncn/api/instl-sncn-service.ts index 2bef72628..4c442a3da 100644 --- a/apps/as/src/entities/instl-sncn/api/instl-sncn-service.ts +++ b/apps/as/src/entities/instl-sncn/api/instl-sncn-service.ts @@ -2,13 +2,15 @@ import { client } from "@/shared/api"; import { ENDPOINT } from "@/shared/config"; import type { PageResponse } from "@/shared/model"; +import type { + InstlSncnApplySaveRequestDto, + InstlSncnMngSaveRequestDto, +} from "../model/instl-sncn-apply-payload-schema"; import type { AdstZoneResponseDto, DocPrgrsUpdateRequestDto, - InstlSncnApplySaveRequestDto, InstlSncnMngDetResponse, InstlSncnMngResponseDto, - InstlSncnMngSaveRequestDto, InstlSncnMngSearchParams, InstlSncnMngService, InstlSncnMngUpdateRequestDto, diff --git a/apps/as/src/entities/instl-sncn/api/queries.ts b/apps/as/src/entities/instl-sncn/api/queries.ts index f9d94dbff..278277668 100644 --- a/apps/as/src/entities/instl-sncn/api/queries.ts +++ b/apps/as/src/entities/instl-sncn/api/queries.ts @@ -3,9 +3,11 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { ENDPOINT } from "@/shared/config"; import type { - DocPrgrsUpdateRequestDto, InstlSncnApplySaveRequestDto, InstlSncnMngSaveRequestDto, +} from "../model/instl-sncn-apply-payload-schema"; +import type { + DocPrgrsUpdateRequestDto, InstlSncnMngSearchParams, InstlSncnMngUpdateRequestDto, } from "../model/instl-sncn-interface"; diff --git a/apps/as/src/entities/instl-sncn/index.ts b/apps/as/src/entities/instl-sncn/index.ts index 946e756f1..ebeb5021b 100644 --- a/apps/as/src/entities/instl-sncn/index.ts +++ b/apps/as/src/entities/instl-sncn/index.ts @@ -19,18 +19,30 @@ export { type ElaprDocPrgrsClientResponseDto, type EsntlAtchFileMngTreeResponseDto, INSTL_SNCN_REGISTER_SELECTION_KEY, - type InstlSncnApplySaveRequestDto, - type InstlSncnBizCstSaveRequestDto, - type InstlSncnBzScaleSaveDto, - type InstlSncnCklstResultSaveDto, - type InstlSncnEsntlAtchFileSaveDto, type InstlSncnMngDetResponse, type InstlSncnMngResponseDto, - type InstlSncnMngSaveRequestDto, type InstlSncnMngSearchParams, type InstlSncnRvwOpnnResponseDto, - type InstlSncnRvwOpnnSaveRequestDto, type InstlSncnSplmntDmndResponseDto, - type InstlSncnSplmntDmndSaveDto, type ReviewStepCode, } from "./model/instl-sncn-interface"; +export type { + InstlSncnApplySaveRequestDto, + InstlSncnBizCstSaveRequestDto, + InstlSncnBzScaleSaveDto, + InstlSncnCklstResultSaveDto, + InstlSncnEsntlAtchFileSaveDto, + InstlSncnMngSaveRequestDto, + InstlSncnRvwOpnnSaveRequestDto, + InstlSncnSplmntDmndSaveDto, +} from "./model/instl-sncn-apply-payload-schema"; +export { + instlSncnApplySaveSchema, + instlSncnBizCstItemSchema, + instlSncnBzScaleItemSchema, + instlSncnCklstResultItemSchema, + instlSncnEsntlAtchFileItemSchema, + instlSncnMngSaveSchema, + instlSncnRvwOpnnSaveSchema, + instlSncnSplmntDmndItemSchema, +} from "./model/instl-sncn-apply-payload-schema"; diff --git a/apps/as/src/entities/instl-sncn/model/instl-sncn-apply-payload-schema.ts b/apps/as/src/entities/instl-sncn/model/instl-sncn-apply-payload-schema.ts new file mode 100644 index 000000000..8e6e17616 --- /dev/null +++ b/apps/as/src/entities/instl-sncn/model/instl-sncn-apply-payload-schema.ts @@ -0,0 +1,108 @@ +import { z } from "zod"; + +/** 백엔드 InstlSncnMngSaveRequestDto */ +export const instlSncnMngSaveSchema = z.object({ + instlSncnDocNo: z.string().optional(), + admdstCd: z.string().optional(), + envoSeComCd: z.string().optional(), + sncnSeComCd: z.string().optional(), + taskSeComCd: z.string().optional(), + bgtBizCd: z.string().optional(), + bgtAplyYr: z.string().optional(), + bizNm: z.string().optional(), + bizBgngYr: z.string().optional(), + bizEndYr: z.string().optional(), + bizCn: z.string().optional(), + aplcntNm: z.string().optional(), + aplcntMblTelno: z.string().optional(), + aplcntOgdpNm: z.string().optional(), + aplcntEmlAddr: z.string().optional(), + dsgnrNm: z.string().optional(), + dsgnrTelno: z.string().optional(), + dsgnrOgdpNm: z.string().optional(), + dsgnrEmlAddr: z.string().optional(), + atchFileGroupId: z.string().optional(), + prgrsSttsComCd: z.string().optional(), + rtlztnFcltSeComCd: z.string().optional(), + rtlztnUsgSeComCd: z.string().optional(), +}); + +/** 백엔드 InstlSncnApplySaveRequestDto.BzScaleItem (diff는 API 미전송) */ +export const instlSncnBzScaleItemSchema = z.object({ + cnstpSeCd: z.string().optional(), + bscPl: z.number().optional(), + budgetReflct: z.number().optional(), + thtiDsgn: z.number().optional(), +}); + +/** 백엔드 InstlSncnApplySaveRequestDto.BizCstItem */ +export const instlSncnBizCstItemSchema = z.object({ + acntgSeCd: z.string().optional(), + bscPlanAmt: z.number().optional(), + bgtRfltAmt: z.number().optional(), + tstmDesignAmt: z.number().optional(), +}); + +/** 백엔드 InstlSncnApplySaveRequestDto.CklstResultItem */ +export const instlSncnCklstResultItemSchema = z.object({ + cklstRvwSn: z.number().optional(), + cklstArtclSn: z.number().optional(), + cklstSn: z.number().optional(), + rvwStpComCd: z.string().nullish(), + selected: z.enum(["Y", "N"]).nullish(), + picRvwCn: z.string().nullish(), +}); + +/** 백엔드 InstlSncnApplySaveRequestDto.EsntlAtchFileItem */ +export const instlSncnEsntlAtchFileItemSchema = z.object({ + esntlAtchFileId: z.string().optional(), + atchFileGroupId: z.string().optional(), +}); + +/** 백엔드 InstlSncnRvwOpnnSaveRequestDto */ +export const instlSncnRvwOpnnSaveSchema = z.object({ + instlSncnDocNo: z.string(), + rvwOpnnSn: z.number().optional(), + opnrSeComCd: z.string().optional(), + opnrNm: z.string().optional(), + rvwRsltCn: z.string().optional(), + rvwRsltAnmlyYn: z.string().optional(), + atchFileGroupId: z.string().optional(), +}); + +/** 백엔드 InstlSncnApplySaveRequestDto.InstlSncnSplmntDmndItem */ +export const instlSncnSplmntDmndItemSchema = z.object({ + splmntDmndSn: z.number().nullish(), + splmntArtclComCd: z.string().nullish(), + splmntDmndCn: z.string().optional(), + splmntDmndDt: z.string().optional(), + splmntDmndAtchFileGroupId: z.string().optional(), + splmntCn: z.string().optional(), + splmntPicNm: z.string().optional(), + splmntCmptnDt: z.string().optional(), + splmntAtchFileGroupId: z.string().optional(), + cmptnYn: z.string().optional(), +}); + +/** 백엔드 InstlSncnApplySaveRequestDto */ +export const instlSncnApplySaveSchema = z.object({ + techReViewSaveCd: z.string().optional(), + rvwStpCd: z.string().optional(), + instlSncnMng: instlSncnMngSaveSchema, + bzScaleList: z.array(instlSncnBzScaleItemSchema).optional(), + bizCstList: z.array(instlSncnBizCstItemSchema).optional(), + cklstResultList: z.array(instlSncnCklstResultItemSchema).optional(), + cklstResultMap: z.record(z.array(instlSncnCklstResultItemSchema)).optional(), + esntlAtchFileList: z.array(instlSncnEsntlAtchFileItemSchema).optional(), + rvwOpnnList: z.array(instlSncnRvwOpnnSaveSchema).optional(), + splmntDmndList: z.array(instlSncnSplmntDmndItemSchema).optional(), +}); + +export type InstlSncnMngSaveRequestDto = z.infer; +export type InstlSncnBzScaleSaveDto = z.infer; +export type InstlSncnBizCstSaveRequestDto = z.infer; +export type InstlSncnCklstResultSaveDto = z.infer; +export type InstlSncnEsntlAtchFileSaveDto = z.infer; +export type InstlSncnRvwOpnnSaveRequestDto = z.infer; +export type InstlSncnSplmntDmndSaveDto = z.infer; +export type InstlSncnApplySaveRequestDto = z.infer; diff --git a/apps/as/src/entities/instl-sncn/model/instl-sncn-interface.ts b/apps/as/src/entities/instl-sncn/model/instl-sncn-interface.ts index a5e4ce791..1eea8c4c9 100644 --- a/apps/as/src/entities/instl-sncn/model/instl-sncn-interface.ts +++ b/apps/as/src/entities/instl-sncn/model/instl-sncn-interface.ts @@ -1,24 +1,24 @@ import type { AtflMngClientResponseDto, - BizCstSaveBase, BizCstTreeDto, BizSclTreeDto, - BzScaleSaveBase, - CklstResultSaveBase, DocPrgrsUpdateRequestDto, ElaprDocPrgrsClientResponseDto, EsntlAtchFileMngTreeResponseDto, - EsntlAtchFileSaveBase, PageableParams, PageResponse, - PbadmsApplySaveHeader, PbadmsMngDetResponseBase, RvwOpnnResponseExtension, - RvwOpnnSaveBase, SplmntDmndResponseExtension, - SplmntDmndSaveBase, } from "@/shared/model"; +import type { + InstlSncnApplySaveRequestDto, + InstlSncnMngSaveRequestDto, + InstlSncnRvwOpnnSaveRequestDto, + InstlSncnSplmntDmndSaveDto, +} from "./instl-sncn-apply-payload-schema"; + export type { AtflMngClientResponseDto, BizCstTreeDto, @@ -41,189 +41,48 @@ export const INSTL_SNCN_REGISTER_SELECTION_KEY = "instlSncnRegisterSelection"; /** 백엔드 InstlSncnMngSearchDto + Pageable */ export interface InstlSncnMngSearchParams extends PageableParams { - /** 설치인가문서번호 */ instlSncnDocNo?: string; - /** 행정구역코드 */ admdstCd?: string; - /** 환경청구분공통코드 */ envoSeComCd?: string; - /** 업무구분공통코드 */ taskSeComCd?: string; - /** 예산사업코드 */ bgtBizCd?: string; - /** 예산신청연도 */ bgtAplyYr?: string; - /** 사업명 */ bizNm?: string; - /** 사업시작연도 */ bizBgngYr?: string; - /** 사업종료연도 */ bizEndYr?: string; - /** 사업내용 */ bizCn?: string; - /** 신청자명 */ aplcntNm?: string; - /** 신청자휴대전화번호 */ aplcntMblTelno?: string; - /** 신청자소속명 */ aplcntOgdpNm?: string; - /** 신청자이메일주소 */ aplcntEmlAddr?: string; - /** 설계자명 */ dsgnrNm?: string; - /** 설계자전화번호 */ dsgnrTelno?: string; - /** 설계자소속명 */ dsgnrOgdpNm?: string; - /** 설계자이메일주소 */ dsgnrEmlAddr?: string; - /** 첨부파일그룹아이디 */ atchFileGroupId?: string; - /** 진행상태공통코드 */ prgrsSttsComCd?: string; } -/** 설치인가관리 저장 요청 DTO */ -export interface InstlSncnMngSaveRequestDto { - /** 설치인가문서번호 */ - instlSncnDocNo?: string; - /** 행정구역코드 */ - admdstCd?: string; - /** 환경청구분공통코드 */ - envoSeComCd?: string; - /** 인가구분공통코드 */ - sncnSeComCd: string; - /** 업무구분공통코드 */ - taskSeComCd: string; - /** 예산사업코드 */ - bgtBizCd?: string; - /** 예산신청연도 */ - bgtAplyYr?: string; - /** 사업명 */ - bizNm: string; - /** 사업시작연도 */ - bizBgngYr: string; - /** 사업종료연도 */ - bizEndYr: string; - /** 사업내용 */ - bizCn: string; - /** 신청자명 */ - aplcntNm?: string; - /** 신청자휴대전화번호 */ - aplcntMblTelno?: string; - /** 신청자소속명 */ - aplcntOgdpNm?: string; - /** 신청자이메일주소 */ - aplcntEmlAddr?: string; - /** 설계자명 */ - dsgnrNm: string; - /** 설계자전화번호 */ - dsgnrTelno: string; - /** 설계자소속명 */ - dsgnrOgdpNm: string; - /** 설계자이메일주소 */ - dsgnrEmlAddr: string; - /** 첨부파일그룹아이디 */ - atchFileGroupId?: string; - /** 진행상태공통코드 */ - prgrsSttsComCd?: string; - /** 재이용시설구분공통코드 */ - rtlztnFcltSeComCd?: string; - /** 재이용용도구분공통코드 */ - rtlztnUsgSeComCd?: string; -} - -/** 설치인가관리 수정 요청 DTO */ +/** 백엔드 InstlSncnMngUpdateRequestDto */ export type InstlSncnMngUpdateRequestDto = InstlSncnMngSaveRequestDto; -/** 설치인가관리 응답 DTO */ -export interface InstlSncnMngResponseDto extends InstlSncnMngSaveRequestDto { - /** 설치인가문서번호 (필수로 재정의) */ +/** 백엔드 InstlSncnMngResponseDto */ +export type InstlSncnMngResponseDto = InstlSncnMngSaveRequestDto & { instlSncnDocNo: string; - /** 환경청구분공통코드명 */ envoSeCdNm: string; - /** 인가구분공통코드명 */ sncnSeCdNm: string; - /** 업무구분공통코드명 */ taskSeCdNm: string; - /** 진행상태공통코드명 */ prgrsSttsCdNm: string; - /** 기술검토회신이력여부 */ techRplyHstryYn: "Y" | "N"; - /** 재이용시설구분공통코드명 */ rtlztnFcltSeComNm: string; - /** 재이용용도구분공통코드명 */ rtlztnUsgSeComNm: string; - /** 등록일시 */ regDt: string; - /** 등록자 UUID */ rgtr: string; - /** 등록자명 */ rgtrNm: string; - /** 수정 일시 */ mdfcnDt: string; - /** 시도 */ sido: string; - /** 구군 */ gugun: string; -} - -/** 설치인가 신청 - 사업규모 저장 DTO(배열 원소) */ -export interface InstlSncnBzScaleSaveDto extends BzScaleSaveBase { - /** 공종구분코드 */ - cnstpSeCd: string; - /** 기본계획수량 */ - bscPl: number; - /** 예산반영수량 */ - budgetReflct: number; - /** 금회설계수량 */ - thtiDsgn: number; - /** 증감(C-B) — 클라이언트 계산용, API 미전송 */ - diff?: number; -} - -/** 설치인가 신청 - 총사업비 저장 DTO(배열 원소) */ -export interface InstlSncnBizCstSaveRequestDto extends BizCstSaveBase { - /** 회계구분코드 */ - acntgSeCd: string; - /** 기본계획금액 */ - bscPlanAmt: number; - /** 예산반영금액 */ - bgtRfltAmt: number; - /** 금회설계금액 */ - tstmDesignAmt: number; -} - -/** 설치인가 신청 - 체크리스트 결과 저장 DTO(배열 원소) */ -export interface InstlSncnCklstResultSaveDto extends CklstResultSaveBase { - /** 점검표일련번호 */ - cklstSn: number; - /** 점검표항목일련번호 */ - cklstArtclSn: number; - /** 점검표검토일련번호 */ - cklstRvwSn: number; - /** 선택값(Y/N/null) */ - selected: "Y" | "N" | null; - /** 담당자검토내용(기술검토의견) */ - picRvwCn?: string | null; -} - -/** 설치인가 신청 - 필수첨부파일 저장 DTO(배열 원소) */ -export interface InstlSncnEsntlAtchFileSaveDto extends EsntlAtchFileSaveBase { - /** 필수첨부파일아이디 */ - esntlAtchFileId: string; - /** 첨부파일그룹아이디 */ - atchFileGroupId: string; -} - -/** 설치인가검토의견 저장 요청 DTO */ -export interface InstlSncnRvwOpnnSaveRequestDto extends RvwOpnnSaveBase { - /** 설치인가문서번호 */ - instlSncnDocNo: string; -} - -/** 설치인가 보완요구 저장 DTO(배열 원소) */ -export type InstlSncnSplmntDmndSaveDto = SplmntDmndSaveBase; +}; /** 설치인가 보완요구 응답 DTO */ export type InstlSncnSplmntDmndResponseDto = InstlSncnSplmntDmndSaveDto & @@ -231,26 +90,6 @@ export type InstlSncnSplmntDmndResponseDto = InstlSncnSplmntDmndSaveDto & instlSncnDocNo?: string; }; -/** 설치인가 신청 - 통합 저장 요청 DTO */ -export interface InstlSncnApplySaveRequestDto extends PbadmsApplySaveHeader { - /** 설치인가관리 정보 */ - instlSncnMng: InstlSncnMngSaveRequestDto; - /** 사업규모 목록 */ - bzScaleList?: InstlSncnBzScaleSaveDto[]; - /** 총사업비 목록 */ - bizCstList?: InstlSncnBizCstSaveRequestDto[]; - /** 체크리스트 검토결과 목록 */ - cklstResultList?: InstlSncnCklstResultSaveDto[]; - /** 체크리스트 검토결과 맵 (rvwStpComCd -> 목록) */ - cklstResultMap?: Record; - /** 필수첨부파일 목록 */ - esntlAtchFileList?: InstlSncnEsntlAtchFileSaveDto[]; - /** 검토의견 목록 */ - rvwOpnnList?: InstlSncnRvwOpnnSaveRequestDto[]; - /** 보완요구 목록 */ - splmntDmndList?: InstlSncnSplmntDmndSaveDto[]; -} - export type ReviewStepCode = "LOCAL" | "ENV" | "KECO"; /** 설치인가검토의견 응답 DTO */ diff --git a/apps/as/src/entities/sewer-bsc-plan/model/sewer-bsc-plan-apply-payload-schema.ts b/apps/as/src/entities/sewer-bsc-plan/model/sewer-bsc-plan-apply-payload-schema.ts index 2980cfffb..6ad7af1ba 100644 --- a/apps/as/src/entities/sewer-bsc-plan/model/sewer-bsc-plan-apply-payload-schema.ts +++ b/apps/as/src/entities/sewer-bsc-plan/model/sewer-bsc-plan-apply-payload-schema.ts @@ -47,7 +47,7 @@ export const sewerBscPlanCklstResultItemSchema = z.object({ cklstArtclSn: z.number().optional(), cklstSn: z.number().optional(), rvwStpComCd: z.string(), - selected: z.string().optional(), + selected: z.enum(["Y", "N"]).nullish(), picRvwCn: z.string().nullish(), }); diff --git a/apps/as/src/pages/design-cnstn/lib/design-cnstn-regist-schema.ts b/apps/as/src/pages/design-cnstn/lib/design-cnstn-regist-schema.ts index 3eecde578..9cbcdc270 100644 --- a/apps/as/src/pages/design-cnstn/lib/design-cnstn-regist-schema.ts +++ b/apps/as/src/pages/design-cnstn/lib/design-cnstn-regist-schema.ts @@ -1,7 +1,13 @@ import { z } from "zod"; +import { + designCnstnBzScaleItemSchema, + designCnstnEsntlAtchFileItemSchema, + designCnstnMngSaveSchema, +} from "@/entities/design-cnstn"; + export const designCnstnRegistSchema = z.object({ - designCnstnMng: z.object({ + designCnstnMng: designCnstnMngSaveSchema.extend({ bizNm: z.string().min(1, "사업명은 필수입니다"), bizBgngYr: z.string().min(1, "사업시작연도는 필수입니다"), bizEndYr: z.string().min(1, "사업종료연도는 필수입니다"), @@ -17,27 +23,11 @@ export const designCnstnRegistSchema = z.object({ .string() .min(1, "설계자 이메일은 필수입니다") .email("올바른 이메일 형식이 아닙니다"), - aplcntNm: z.string().optional(), - aplcntMblTelno: z.string().optional(), - aplcntOgdpNm: z.string().optional(), - aplcntEmlAddr: z.string().optional(), - designCnstnDocNo: z.string().optional(), - admdstCd: z.string().optional(), - envoSeComCd: z.string().optional(), - prgrsSttsComCd: z.string().optional(), - atchFileGroupId: z.string().optional(), - envoSeCdNm: z.string().optional(), - taskSeCdNm: z.string().optional(), - prgrsSttsCdNm: z.string().optional(), sido: z.string().optional(), gugun: z.string().optional(), - regDt: z.string().optional(), - rgtr: z.string().optional(), - rgtrNm: z.string().optional(), - mdfcnDt: z.string().optional(), }), bzScaleList: z.array( - z.object({ + designCnstnBzScaleItemSchema.extend({ cnstpSeCd: z.string(), bscPl: z.number(), budgetReflct: z.number(), @@ -46,7 +36,7 @@ export const designCnstnRegistSchema = z.object({ }), ), esntlAtchFileList: z.array( - z.object({ + designCnstnEsntlAtchFileItemSchema.extend({ esntlAtchFileId: z.string(), atchFileGroupId: z.string(), }), diff --git a/apps/as/src/pages/design-cnstn/lib/form-data-mapper.ts b/apps/as/src/pages/design-cnstn/lib/form-data-mapper.ts index 3150bfaa7..326f6e237 100644 --- a/apps/as/src/pages/design-cnstn/lib/form-data-mapper.ts +++ b/apps/as/src/pages/design-cnstn/lib/form-data-mapper.ts @@ -1,9 +1,13 @@ import type { IUserInfo } from "@/shared/store"; -import type { DesignCnstnMngDetResponseDto } from "@/entities/design-cnstn"; +import { + type DesignCnstnApplySaveRequestDto, + designCnstnApplySaveSchema, + type DesignCnstnMngDetResponseDto, +} from "@/entities/design-cnstn"; import { toEsntlAtchFileSaveList } from "@/widgets/pbadms-sprt"; import type { DesignCnstnRegistFormData } from "./design-cnstn-regist-schema"; -import { parseTaskSeComCdFromApi } from "./design-cnstn-regist-schema"; +import { formatTaskSeComCdForApi, parseTaskSeComCdFromApi } from "./design-cnstn-regist-schema"; export function mapDetailToFormData(data: DesignCnstnMngDetResponseDto): DesignCnstnRegistFormData { const detDto = data.detDto; @@ -33,15 +37,8 @@ export function mapDetailToFormData(data: DesignCnstnMngDetResponseDto): DesignC envoSeComCd: detDto.envoSeComCd, prgrsSttsComCd: detDto.prgrsSttsComCd, atchFileGroupId: detDto.atchFileGroupId ?? "", - envoSeCdNm: detDto.envoSeCdNm, - taskSeCdNm: detDto.taskSeCdNm, - prgrsSttsCdNm: detDto.prgrsSttsCdNm, sido: detDto.sido, gugun: detDto.gugun, - regDt: detDto.regDt, - rgtr: detDto.rgtr, - rgtrNm: detDto.rgtrNm, - mdfcnDt: detDto.mdfcnDt, }, bzScaleList: bizSclList.map((item) => ({ cnstpSeCd: item.cnstpSeCd, @@ -90,3 +87,20 @@ export function getCreateDefaultValues( privacyConsent: "N", }; } + +export function buildFormPayload( + data: DesignCnstnRegistFormData, + prgrsSttsComCd: "CV" | "CT", + options: { isEditMode: boolean; docNo?: string }, +): DesignCnstnApplySaveRequestDto { + return designCnstnApplySaveSchema.parse({ + designCnstnMng: { + ...data.designCnstnMng, + taskSeComCd: formatTaskSeComCdForApi(data.designCnstnMng.taskSeComCd), + designCnstnDocNo: options.isEditMode ? options.docNo : undefined, + prgrsSttsComCd, + }, + bzScaleList: data.bzScaleList, + esntlAtchFileList: data.esntlAtchFileList, + }); +} diff --git a/apps/as/src/pages/design-cnstn/lib/save-payload-utils.ts b/apps/as/src/pages/design-cnstn/lib/save-payload-utils.ts index 48da7a731..625ff0486 100644 --- a/apps/as/src/pages/design-cnstn/lib/save-payload-utils.ts +++ b/apps/as/src/pages/design-cnstn/lib/save-payload-utils.ts @@ -4,6 +4,7 @@ import type { DesignCnstnApplySaveRequestDto, DesignCnstnMngDetResponseDto, } from "@/entities/design-cnstn"; +import { designCnstnApplySaveSchema } from "@/entities/design-cnstn"; import { toEsntlAtchFileSaveList } from "@/widgets/pbadms-sprt"; import type { ReviewStepCode } from "../model/view-types"; @@ -30,11 +31,11 @@ export function buildSavePayload( throw new Error("상세 정보(detDto)가 없습니다."); } - return { + return designCnstnApplySaveSchema.parse({ designCnstnMng: { ...detDto, prgrsSttsComCd }, bzScaleList: toBzScaleSaveDto(data.bizSclList ?? []), esntlAtchFileList: toEsntlAtchFileSaveList(data.esntlFileList), - }; + }); } export function buildTechReviewPayload( @@ -45,10 +46,10 @@ export function buildTechReviewPayload( reviewOpinionFormData?: ReviewOpinionGetFormDataResult | null, opnrNm?: string, ): DesignCnstnApplySaveRequestDto { - return { + return designCnstnApplySaveSchema.parse({ ...buildSavePayload(data, prgrsSttsComCd), techReViewSaveCd, rvwStpCd: reviewStep, rvwOpnnList: toRvwOpnnSaveDto(data, reviewOpinionFormData, opnrNm), - }; + }); } diff --git a/apps/as/src/pages/design-cnstn/ui/design-form-page.tsx b/apps/as/src/pages/design-cnstn/ui/design-form-page.tsx index 041e1d812..7e0519db1 100644 --- a/apps/as/src/pages/design-cnstn/ui/design-form-page.tsx +++ b/apps/as/src/pages/design-cnstn/ui/design-form-page.tsx @@ -11,7 +11,6 @@ import { useQueryClient } from "@tanstack/react-query"; import { useAlertStore, useUserStore } from "@/shared/lib"; import { SectionCollapsibleGroup, SectionCollapsibleToggle } from "@/shared/ui"; import { - type DesignCnstnApplySaveRequestDto, designCnstnKeys, type DesignCnstnMngDetResponseDto, designCnstnMngService, @@ -27,12 +26,12 @@ import { } from "@/widgets/pbadms-sprt"; import { Button } from "@common/components"; +import { type DesignCnstnRegistFormData, designCnstnRegistSchema } from "../lib/design-cnstn-regist-schema"; import { - type DesignCnstnRegistFormData, - designCnstnRegistSchema, - formatTaskSeComCdForApi, -} from "../lib/design-cnstn-regist-schema"; -import { getCreateDefaultValues, mapDetailToFormData } from "../lib/form-data-mapper"; + buildFormPayload, + getCreateDefaultValues, + mapDetailToFormData, +} from "../lib/form-data-mapper"; import { PROGRESS_STATUS_COLUMNS } from "../model/columns"; import { BasicInfoFormSection } from "./sections/basic-info-form-section"; @@ -68,29 +67,18 @@ function DesignFormPage({ mode, initialData, createDefaults }: DesignFormPagePro : getCreateDefaultValues(userInfo, createDefaults), }); - function buildFormPayload( - data: DesignCnstnRegistFormData, - prgrsSttsComCd: "CV" | "CT", - ): DesignCnstnApplySaveRequestDto { - const { taskSeComCd: formTaskSeComCd, ...designCnstnMngRest } = data.designCnstnMng; - - return { - designCnstnMng: { - ...designCnstnMngRest, - taskSeComCd: formatTaskSeComCdForApi(formTaskSeComCd), - designCnstnDocNo: isEditMode ? initialData?.detDto?.designCnstnDocNo : undefined, - prgrsSttsComCd, - }, - bzScaleList: data.bzScaleList, - esntlAtchFileList: data.esntlAtchFileList, - }; + function createFormPayload(data: DesignCnstnRegistFormData, prgrsSttsComCd: "CV" | "CT") { + return buildFormPayload(data, prgrsSttsComCd, { + isEditMode, + docNo: initialData?.detDto?.designCnstnDocNo, + }); } async function submitForm( data: DesignCnstnRegistFormData, prgrsSttsComCd: "CV" | "CT", ): Promise { - return designCnstnMngService.saveApply(buildFormPayload(data, prgrsSttsComCd)); + return designCnstnMngService.saveApply(createFormPayload(data, prgrsSttsComCd)); } async function onSave(data: DesignCnstnRegistFormData) { diff --git a/apps/as/src/pages/fnrs-cnsltn/lib/fnrs-cnsltn-regist-schema.ts b/apps/as/src/pages/fnrs-cnsltn/lib/fnrs-cnsltn-regist-schema.ts index 21668e8b8..5739c8e6e 100644 --- a/apps/as/src/pages/fnrs-cnsltn/lib/fnrs-cnsltn-regist-schema.ts +++ b/apps/as/src/pages/fnrs-cnsltn/lib/fnrs-cnsltn-regist-schema.ts @@ -1,14 +1,22 @@ import { z } from "zod"; +import { + fnrsCnsltnBizCstItemSchema, + fnrsCnsltnBzScaleItemSchema, + fnrsCnsltnCklstResultItemSchema, + fnrsCnsltnEsntlAtchFileItemSchema, + fnrsCnsltnMngSaveSchema, + fnrsCnsltnSplmntDmndItemSchema, + fnrsSharItemSchema, +} from "@/entities/fnrs-cnsltn"; + export const fnrsCnsltnRegistSchema = z.object({ - fnrsCnsltnMng: z.object({ + fnrsCnsltnMng: fnrsCnsltnMngSaveSchema.extend({ bizNm: z.string().min(1, "사업명은 필수입니다"), bizBgngYr: z.string().min(1, "사업시작연도는 필수입니다"), bizEndYr: z.string().min(1, "사업종료연도는 필수입니다"), bizCn: z.string().min(1, "사업내용은 필수입니다"), taskSeComCd: z.array(z.string()).min(1, "구분은 필수입니다"), - cfmtnBgtBizNo: z.string().optional(), - bgtAplyYr: z.string().optional(), dsgnrNm: z.string().min(1, "설계자 이름은 필수입니다"), dsgnrTelno: z .string() @@ -19,30 +27,11 @@ export const fnrsCnsltnRegistSchema = z.object({ .string() .min(1, "설계자 이메일은 필수입니다") .email("올바른 이메일 형식이 아닙니다"), - aplcntNm: z.string().optional(), - aplcntMblTelno: z.string().optional(), - aplcntOgdpNm: z.string().optional(), - aplcntEmlAddr: z.string().optional(), - fnrsCnsltnDocNo: z.string().optional(), - admdstCd: z.string().optional(), - envoSeComCd: z.string().optional(), - rtlztnFcltSeComCd: z.string().optional(), - rtlztnUsgSeComCd: z.string().optional(), - prgrsSttsComCd: z.string().optional(), - atchFileGroupId: z.string().optional(), - sharAtchFileGroupId: z.string().optional(), - envoSeCdNm: z.string().optional(), - taskSeCdNm: z.string().optional(), - prgrsSttsCdNm: z.string().optional(), sido: z.string().optional(), gugun: z.string().optional(), - regDt: z.string().optional(), - rgtr: z.string().optional(), - rgtrNm: z.string().optional(), - mdfcnDt: z.string().optional(), }), bzScaleList: z.array( - z.object({ + fnrsCnsltnBzScaleItemSchema.extend({ cnstpSeCd: z.string(), bscPl: z.number(), budgetReflct: z.number(), @@ -51,7 +40,7 @@ export const fnrsCnsltnRegistSchema = z.object({ }), ), bizCstList: z.array( - z.object({ + fnrsCnsltnBizCstItemSchema.extend({ acntgSeCd: z.string(), bscPlanAmt: z.number(), bgtRfltAmt: z.number(), @@ -59,7 +48,7 @@ export const fnrsCnsltnRegistSchema = z.object({ }), ), fnrsSharList: z.array( - z.object({ + fnrsSharItemSchema.extend({ fnrsSharSeCd: z.string(), exstnAmt: z.number(), chgRqtAmt: z.number(), @@ -68,37 +57,24 @@ export const fnrsCnsltnRegistSchema = z.object({ }), ), cklstResultList: z.array( - z.object({ + fnrsCnsltnCklstResultItemSchema.extend({ cklstSn: z.number(), cklstArtclSn: z.number(), cklstRvwSn: z.number(), - rvwStpComCd: z.string().nullish(), - selected: z.enum(["Y", "N"]).nullable(), + selected: z.enum(["Y", "N"]).nullish(), picRvwCn: z.string().nullish(), }), ), esntlAtchFileList: z.array( - z.object({ + fnrsCnsltnEsntlAtchFileItemSchema.extend({ esntlAtchFileId: z.string(), atchFileGroupId: z.string(), }), ), splmntDmndList: z.array( - z.object({ - splmntDmndSn: z.number().nullish(), - splmntArtclComCd: z.string().nullish(), + fnrsCnsltnSplmntDmndItemSchema.extend({ splmntArtclCdNm: z.string().nullish(), - splmntDmndCn: z.string().optional(), - splmntDmndDt: z.string().optional(), - splmntDmndAtchFileGroupId: z.string().optional(), splmntDmndAtchFileNm: z.string().optional(), - splmntCn: z.string().optional(), - splmntPicNm: z.string().optional(), - splmntCmptnDt: z.string().optional(), - splmntAtchFileGroupId: z.string().optional(), - splmntAtchFileNm: z.string().optional(), - splmntAtchFileAtflId: z.string().optional(), - cmptnYn: z.string().optional(), }), ), privacyConsent: z.enum(["Y", "N"], { diff --git a/apps/as/src/pages/fnrs-cnsltn/lib/form-data-mapper.ts b/apps/as/src/pages/fnrs-cnsltn/lib/form-data-mapper.ts index 09e4817f5..1e5c6902d 100644 --- a/apps/as/src/pages/fnrs-cnsltn/lib/form-data-mapper.ts +++ b/apps/as/src/pages/fnrs-cnsltn/lib/form-data-mapper.ts @@ -1,9 +1,21 @@ import type { IUserInfo } from "@/shared/store"; -import type { FnrsCnsltnMngDetResponseDto } from "@/entities/fnrs-cnsltn"; -import { mapFnrsSharDetToFormList, toEsntlAtchFileSaveList } from "@/widgets/pbadms-sprt"; +import { + type FnrsCnsltnApplySaveRequestDto, + fnrsCnsltnApplySaveSchema, + type FnrsCnsltnMngDetResponseDto, +} from "@/entities/fnrs-cnsltn"; +import { + type CostItemDef, + type FnrsSharItemDef, + mapFnrsSharDetToFormList, + recalculateFnrsSharTotals, + toEsntlAtchFileSaveList, + toFnrsSharSaveList, + validateBizCstSharBalance, +} from "@/widgets/pbadms-sprt"; import type { FnrsCnsltnRegistFormData } from "./fnrs-cnsltn-regist-schema"; -import { parseTaskSeComCdFromApi } from "./fnrs-cnsltn-regist-schema"; +import { formatTaskSeComCdForApi, parseTaskSeComCdFromApi } from "./fnrs-cnsltn-regist-schema"; function mapSelectedValue(value?: string | null): "Y" | "N" | null { if (value === "Y" || value === "N") return value; @@ -47,15 +59,8 @@ export function mapDetailToFormData(data: FnrsCnsltnMngDetResponseDto): FnrsCnsl prgrsSttsComCd: detDto.prgrsSttsComCd, atchFileGroupId: detDto.atchFileGroupId ?? "", sharAtchFileGroupId: detDto.sharAtchFileGroupId ?? "", - envoSeCdNm: detDto.envoSeCdNm, - taskSeCdNm: detDto.taskSeCdNm, - prgrsSttsCdNm: detDto.prgrsSttsCdNm, sido: detDto.sido, gugun: detDto.gugun, - regDt: detDto.regDt, - rgtr: detDto.rgtr, - rgtrNm: detDto.rgtrNm, - mdfcnDt: detDto.mdfcnDt, }, bzScaleList: bizSclList.map((item) => ({ cnstpSeCd: item.cnstpSeCd, @@ -94,8 +99,6 @@ export function mapDetailToFormData(data: FnrsCnsltnMngDetResponseDto): FnrsCnsl splmntPicNm: item.splmntPicNm ?? "", splmntCmptnDt: item.splmntCmptnDt ?? "", splmntAtchFileGroupId: item.splmntAtchFileGroupId ?? "", - splmntAtchFileNm: item.splmntAtchFileInfo?.orgnlFileNm ?? "", - splmntAtchFileAtflId: item.splmntAtchFileInfo?.atflId ?? "", cmptnYn: item.cmptnYn, })) ?? [], privacyConsent: "Y", @@ -146,3 +149,46 @@ export function getCreateDefaultValues( privacyConsent: "N", }; } + +export function buildFormPayload( + data: FnrsCnsltnRegistFormData, + prgrsSttsComCd: string, + options: { + isEditMode: boolean; + docNo?: string; + sharItems: FnrsSharItemDef[]; + costItems: CostItemDef[]; + }, +): FnrsCnsltnApplySaveRequestDto | { validationMessage: string } { + const withTotals = recalculateFnrsSharTotals(data.fnrsSharList, options.sharItems); + const validationMessage = validateBizCstSharBalance( + data.bizCstList, + withTotals, + options.sharItems, + options.costItems, + ); + if (validationMessage) { + return { validationMessage }; + } + + return fnrsCnsltnApplySaveSchema.parse({ + fnrsCnsltnMng: { + ...data.fnrsCnsltnMng, + taskSeComCd: formatTaskSeComCdForApi(data.fnrsCnsltnMng.taskSeComCd), + fnrsCnsltnDocNo: options.isEditMode ? options.docNo : undefined, + prgrsSttsComCd, + }, + bzScaleList: data.bzScaleList, + bizCstList: data.bizCstList, + fnrsSharList: toFnrsSharSaveList(withTotals), + cklstResultList: data.cklstResultList.map((item) => ({ + ...item, + selected: item.selected ?? undefined, + })), + esntlAtchFileList: data.esntlAtchFileList, + splmntDmndList: data.splmntDmndList.map((item) => ({ + ...item, + ...(prgrsSttsComCd !== "SV" && prgrsSttsComCd !== "ST" && { cmptnYn: "Y" }), + })), + }); +} diff --git a/apps/as/src/pages/fnrs-cnsltn/lib/save-payload-utils.ts b/apps/as/src/pages/fnrs-cnsltn/lib/save-payload-utils.ts index 39ebd7582..c4d7d5d88 100644 --- a/apps/as/src/pages/fnrs-cnsltn/lib/save-payload-utils.ts +++ b/apps/as/src/pages/fnrs-cnsltn/lib/save-payload-utils.ts @@ -10,6 +10,7 @@ import type { FnrsCnsltnMngResponseDto, FnrsCnsltnSplmntDmndItem, } from "@/entities/fnrs-cnsltn"; +import { fnrsCnsltnApplySaveSchema } from "@/entities/fnrs-cnsltn"; import type { PwrkCnsltnCnsltnResponseDto } from "@/entities/pwrk-cnsltn-mng"; import { mapFnrsSharDetToFormList, @@ -61,14 +62,14 @@ export function buildSavePayload( const cklstResultList = data.cklstResultList ?? []; const esntlFileList = data.esntlFileList ?? []; - return { + return fnrsCnsltnApplySaveSchema.parse({ fnrsCnsltnMng: { ...detDto, prgrsSttsComCd }, bzScaleList: toBzScaleSaveDto(bizSclList), bizCstList: toBizCstSaveDto(bizCstList), cklstResultList: toCklstSaveDto(cklstResultList, checklistFormState, reviewStep), esntlAtchFileList: toEsntlAtchFileSaveList(esntlFileList), fnrsSharList: toFnrsSharSaveList(mapFnrsSharDetToFormList(data.fnrsSharList ?? [])), - }; + }); } export function buildTechReviewReplyPayload( @@ -80,12 +81,12 @@ export function buildTechReviewReplyPayload( reviewOpinionFormData?: ReviewOpinionGetFormDataResult | null, opnrNm?: string, ): FnrsCnsltnApplySaveRequestDto { - return { + return fnrsCnsltnApplySaveSchema.parse({ ...buildSavePayload(data, checklistFormState, reviewStep, prgrsSttsComCd), techReViewSaveCd, rvwStpCd: reviewStep, rvwOpnnList: toRvwOpnnSaveDto(data, reviewOpinionFormData, opnrNm), - }; + }); } export function buildSupplementReqPayload( @@ -107,10 +108,10 @@ export function buildSupplementReqPayload( cmptnYn: "N", })); - return { + return fnrsCnsltnApplySaveSchema.parse({ ...buildSavePayload(data, checklistFormState, "LOCAL", "SL"), splmntDmndList: [...existingItems, ...newItems], - }; + }); } export function buildFileSplmntReqPayload( @@ -124,10 +125,10 @@ export function buildFileSplmntReqPayload( cmptnYn: "N", })); - return { + return fnrsCnsltnApplySaveSchema.parse({ ...buildSavePayload(data, checklistFormState, "LOCAL", "SL"), splmntDmndList: [...newItems], - }; + }); } export function buildRvwRsltSplmntReqPayload( @@ -144,10 +145,10 @@ export function buildRvwRsltSplmntReqPayload( cmptnYn: "N", })); - return { + return fnrsCnsltnApplySaveSchema.parse({ ...buildSavePayload(data, checklistFormState, "LOCAL", "SL"), splmntDmndList: [...existingItems, ...newItems], - }; + }); } export function toSplmntDmndSaveItem(item: FnrsCnsltnSplmntDmndItem): FnrsCnsltnSplmntDmndItem { @@ -169,21 +170,21 @@ export function buildSupplementSubmitPayload( data: FnrsCnsltnMngDetResponseDto, checklistFormState: ChecklistFormState, ): FnrsCnsltnApplySaveRequestDto { - return { + return fnrsCnsltnApplySaveSchema.parse({ ...buildSavePayload(data, checklistFormState, "LOCAL", "SL"), - splmntDmndList: data.splmntDmndList, - }; + splmntDmndList: (data.splmntDmndList ?? []).map(toSplmntDmndSaveItem), + }); } export function buildTechReviewPayload( det: FnrsCnsltnMngResponseDto, cklstResultList: CklstResultItem[], ): FnrsCnsltnApplySaveRequestDto { - return { + return fnrsCnsltnApplySaveSchema.parse({ fnrsCnsltnMng: { ...det, prgrsSttsComCd: "ER" }, bzScaleList: [], bizCstList: [], cklstResultList, esntlAtchFileList: [], - }; + }); } diff --git a/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-form-page.tsx b/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-form-page.tsx index cac88ea86..28a9a0a51 100644 --- a/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-form-page.tsx +++ b/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-form-page.tsx @@ -13,7 +13,6 @@ import { SectionCollapsibleGroup, SectionCollapsibleToggle } from "@/shared/ui"; import { useAcntgSeMngTree } from "@/entities/acntg"; import { useEsntlAtchFileMngTree } from "@/entities/esntl"; import { - type FnrsCnsltnApplySaveRequestDto, fnrsCnsltnKeys, type FnrsCnsltnMngDetResponseDto, fnrsCnsltnMngService, @@ -32,19 +31,16 @@ import { isFormEsntlAtchComplete, PrivacyConsentSection, ProgressStatusSection, - recalculateFnrsSharTotals, SplmntDmndFormSection, - toFnrsSharSaveList, - validateBizCstSharBalance, } from "@/widgets/pbadms-sprt"; import { Button } from "@common/components"; +import { type FnrsCnsltnRegistFormData, fnrsCnsltnRegistSchema } from "../lib/fnrs-cnsltn-regist-schema"; import { - type FnrsCnsltnRegistFormData, - fnrsCnsltnRegistSchema, - formatTaskSeComCdForApi, -} from "../lib/fnrs-cnsltn-regist-schema"; -import { getCreateDefaultValues, mapDetailToFormData } from "../lib/form-data-mapper"; + buildFormPayload, + getCreateDefaultValues, + mapDetailToFormData, +} from "../lib/form-data-mapper"; import { PROGRESS_STATUS_COLUMNS } from "../model/columns"; import { PwrkCnsltnDocMngDialog } from "./components/pwrk-cnsltn-doc-mng-dialog"; @@ -89,54 +85,25 @@ function FnrsFormPage({ mode, initialData, createDefaults }: FnrsFormPageProps) : getCreateDefaultValues(userInfo, createDefaults), }); - function buildFormPayload( - data: FnrsCnsltnRegistFormData, - prgrsSttsComCd: string, - ): FnrsCnsltnApplySaveRequestDto | undefined { - const withTotals = recalculateFnrsSharTotals(data.fnrsSharList, sharItems); - const validationMessage = validateBizCstSharBalance( - data.bizCstList, - withTotals, + function createFormPayload(data: FnrsCnsltnRegistFormData, prgrsSttsComCd: string) { + const result = buildFormPayload(data, prgrsSttsComCd, { + isEditMode, + docNo: initialData?.detDto?.fnrsCnsltnDocNo, sharItems, costItems, - ); - if (validationMessage) { - alert(validationMessage); + }); + if ("validationMessage" in result) { + alert(result.validationMessage); return undefined; } - - const { taskSeComCd: formTaskSeComCd, ...fnrsCnsltnMngRest } = data.fnrsCnsltnMng; - - return { - fnrsCnsltnMng: { - ...fnrsCnsltnMngRest, - taskSeComCd: formatTaskSeComCdForApi(formTaskSeComCd), - fnrsCnsltnDocNo: isEditMode ? initialData?.detDto?.fnrsCnsltnDocNo : undefined, - prgrsSttsComCd, - }, - bzScaleList: data.bzScaleList, - bizCstList: data.bizCstList, - fnrsSharList: toFnrsSharSaveList(withTotals), - cklstResultList: data.cklstResultList.map((item) => ({ - ...item, - selected: item.selected ?? undefined, - })), - esntlAtchFileList: data.esntlAtchFileList, - splmntDmndList: data.splmntDmndList.map( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - ({ splmntAtchFileNm, splmntAtchFileAtflId, splmntDmndAtchFileNm, ...item }) => ({ - ...item, - ...(prgrsSttsComCd !== "SV" && prgrsSttsComCd !== "ST" && { cmptnYn: "Y" }), - }), - ), - }; + return result; } async function submitForm( data: FnrsCnsltnRegistFormData, prgrsSttsComCd: "SV" | "ST", ): Promise { - const payload = buildFormPayload(data, prgrsSttsComCd); + const payload = createFormPayload(data, prgrsSttsComCd); if (!payload) return undefined; return fnrsCnsltnMngService.saveApply(payload); } @@ -146,7 +113,7 @@ function FnrsFormPage({ mode, initialData, createDefaults }: FnrsFormPageProps) if (!beforePrgrsSttsComCd) return undefined; const docNo = initialData?.detDto?.fnrsCnsltnDocNo; - const payload = buildFormPayload(data, beforePrgrsSttsComCd); + const payload = createFormPayload(data, beforePrgrsSttsComCd); if (!docNo || !payload) return undefined; return fnrsCnsltnMngService.submitSupplement(docNo, payload); diff --git a/apps/as/src/pages/instl-sncn/lib/form-data-mapper.ts b/apps/as/src/pages/instl-sncn/lib/form-data-mapper.ts index 4dfdf8685..5a3797918 100644 --- a/apps/as/src/pages/instl-sncn/lib/form-data-mapper.ts +++ b/apps/as/src/pages/instl-sncn/lib/form-data-mapper.ts @@ -1,9 +1,13 @@ import type { IUserInfo } from "@/shared/store/user-store"; -import type { InstlSncnMngDetResponse } from "@/entities/instl-sncn"; +import { + type InstlSncnApplySaveRequestDto, + instlSncnApplySaveSchema, + type InstlSncnMngDetResponse, +} from "@/entities/instl-sncn"; import { toEsntlAtchFileSaveList } from "@/widgets/pbadms-sprt"; import type { InstlSncnRegistFormData } from "./instl-sncn-regist-schema"; -import { parseTaskSeComCdFromApi } from "./instl-sncn-regist-schema"; +import { formatTaskSeComCdForApi, parseTaskSeComCdFromApi } from "./instl-sncn-regist-schema"; function mapSelectedValue(value?: string | null): "Y" | "N" | null { if (value === "Y" || value === "N") return value; @@ -16,12 +20,12 @@ export function mapDetailToFormData(data: InstlSncnMngDetResponse): InstlSncnReg return { instlSncnMng: { instlSncnDocNo: detDto.instlSncnDocNo, - bizNm: detDto.bizNm, - bizBgngYr: detDto.bizBgngYr, - bizEndYr: detDto.bizEndYr, - bizCn: detDto.bizCn, + bizNm: detDto.bizNm ?? "", + bizBgngYr: detDto.bizBgngYr ?? "", + bizEndYr: detDto.bizEndYr ?? "", + bizCn: detDto.bizCn ?? "", taskSeComCd: parseTaskSeComCdFromApi(detDto.taskSeComCd), - sncnSeComCd: detDto.sncnSeComCd, + sncnSeComCd: detDto.sncnSeComCd ?? "", dsgnrNm: detDto.dsgnrNm ?? "", dsgnrTelno: detDto.dsgnrTelno ?? "", dsgnrOgdpNm: detDto.dsgnrOgdpNm ?? "", @@ -38,16 +42,8 @@ export function mapDetailToFormData(data: InstlSncnMngDetResponse): InstlSncnReg atchFileGroupId: detDto.atchFileGroupId ?? "", rtlztnFcltSeComCd: detDto.rtlztnFcltSeComCd ?? "", rtlztnUsgSeComCd: detDto.rtlztnUsgSeComCd ?? "", - envoSeCdNm: detDto.envoSeCdNm, - sncnSeCdNm: detDto.sncnSeCdNm, - taskSeCdNm: detDto.taskSeCdNm, - prgrsSttsCdNm: detDto.prgrsSttsCdNm, sido: detDto.sido, gugun: detDto.gugun, - regDt: detDto.regDt, - rgtr: detDto.rgtr, - rgtrNm: detDto.rgtrNm, - mdfcnDt: detDto.mdfcnDt, }, bzScaleList: bizSclList.map((item) => ({ cnstpSeCd: item.cnstpSeCd, @@ -85,8 +81,6 @@ export function mapDetailToFormData(data: InstlSncnMngDetResponse): InstlSncnReg splmntPicNm: item.splmntPicNm ?? "", splmntCmptnDt: item.splmntCmptnDt ?? "", splmntAtchFileGroupId: item.splmntAtchFileGroupId ?? "", - splmntAtchFileNm: item.splmntAtchFileInfo?.orgnlFileNm ?? "", - splmntAtchFileAtflId: item.splmntAtchFileInfo?.atflId ?? "", cmptnYn: item.cmptnYn, })) ?? [], privacyConsent: "Y", @@ -132,3 +126,29 @@ export function getCreateDefaultValues( privacyConsent: "N", }; } + +export function buildFormPayload( + data: InstlSncnRegistFormData, + prgrsSttsComCd: "SV" | "ST" | "TE", + options: { isEditMode: boolean; docNo?: string }, +): InstlSncnApplySaveRequestDto { + return instlSncnApplySaveSchema.parse({ + instlSncnMng: { + ...data.instlSncnMng, + instlSncnDocNo: options.isEditMode ? options.docNo : undefined, + taskSeComCd: formatTaskSeComCdForApi(data.instlSncnMng.taskSeComCd), + prgrsSttsComCd, + }, + bzScaleList: data.bzScaleList, + bizCstList: data.bizCstList, + cklstResultList: data.cklstResultList.map((item) => ({ + ...item, + selected: item.selected ?? undefined, + })), + esntlAtchFileList: data.esntlAtchFileList, + splmntDmndList: data.splmntDmndList.map((item) => ({ + ...item, + ...(prgrsSttsComCd === "TE" ? { cmptnYn: "Y" } : null), + })), + }); +} diff --git a/apps/as/src/pages/instl-sncn/lib/instl-sncn-regist-schema.ts b/apps/as/src/pages/instl-sncn/lib/instl-sncn-regist-schema.ts index 755d3df63..befd61c4e 100644 --- a/apps/as/src/pages/instl-sncn/lib/instl-sncn-regist-schema.ts +++ b/apps/as/src/pages/instl-sncn/lib/instl-sncn-regist-schema.ts @@ -1,7 +1,16 @@ import { z } from "zod"; +import { + instlSncnBizCstItemSchema, + instlSncnBzScaleItemSchema, + instlSncnCklstResultItemSchema, + instlSncnEsntlAtchFileItemSchema, + instlSncnMngSaveSchema, + instlSncnSplmntDmndItemSchema, +} from "@/entities/instl-sncn"; + export const instlSncnRegistSchema = z.object({ - instlSncnMng: z.object({ + instlSncnMng: instlSncnMngSaveSchema.extend({ bizNm: z.string().min(1, "사업명은 필수입니다"), bizBgngYr: z.string().min(1, "사업시작연도는 필수입니다"), bizEndYr: z.string().min(1, "사업종료연도는 필수입니다"), @@ -18,32 +27,13 @@ export const instlSncnRegistSchema = z.object({ .string() .min(1, "설계자 이메일은 필수입니다") .email("올바른 이메일 형식이 아닙니다"), - bgtBizCd: z.string().optional(), - bgtAplyYr: z.string().optional(), - aplcntNm: z.string().optional(), - aplcntMblTelno: z.string().optional(), - aplcntOgdpNm: z.string().optional(), - aplcntEmlAddr: z.string().optional(), instlSncnDocNo: z.string().nullish(), - admdstCd: z.string().optional(), - envoSeComCd: z.string().optional(), prgrsSttsComCd: z.string().nullish(), - atchFileGroupId: z.string().optional(), - rtlztnFcltSeComCd: z.string().optional(), - rtlztnUsgSeComCd: z.string().optional(), - envoSeCdNm: z.string().nullish(), - sncnSeCdNm: z.string().nullish(), - taskSeCdNm: z.string().nullish(), - prgrsSttsCdNm: z.string().nullish(), sido: z.string().nullish(), gugun: z.string().nullish(), - regDt: z.string().nullish(), - rgtr: z.string().nullish(), - rgtrNm: z.string().nullish(), - mdfcnDt: z.string().nullish(), }), bzScaleList: z.array( - z.object({ + instlSncnBzScaleItemSchema.extend({ cnstpSeCd: z.string(), bscPl: z.number(), budgetReflct: z.number(), @@ -52,7 +42,7 @@ export const instlSncnRegistSchema = z.object({ }), ), bizCstList: z.array( - z.object({ + instlSncnBizCstItemSchema.extend({ acntgSeCd: z.string(), bscPlanAmt: z.number(), bgtRfltAmt: z.number(), @@ -60,37 +50,25 @@ export const instlSncnRegistSchema = z.object({ }), ), cklstResultList: z.array( - z.object({ + instlSncnCklstResultItemSchema.extend({ cklstSn: z.number(), cklstArtclSn: z.number(), cklstRvwSn: z.number(), rvwStpComCd: z.string(), - selected: z.enum(["Y", "N"]).nullable(), + selected: z.enum(["Y", "N"]).nullish(), picRvwCn: z.string().nullish(), }), ), esntlAtchFileList: z.array( - z.object({ + instlSncnEsntlAtchFileItemSchema.extend({ esntlAtchFileId: z.string(), atchFileGroupId: z.string(), }), ), splmntDmndList: z.array( - z.object({ - splmntDmndSn: z.number().nullish(), - splmntArtclComCd: z.string().nullish(), + instlSncnSplmntDmndItemSchema.extend({ splmntArtclCdNm: z.string().nullish(), - splmntDmndCn: z.string().optional(), - splmntDmndDt: z.string().optional(), - splmntDmndAtchFileGroupId: z.string().optional(), splmntDmndAtchFileNm: z.string().optional(), - splmntCn: z.string().optional(), - splmntPicNm: z.string().optional(), - splmntCmptnDt: z.string().optional(), - splmntAtchFileGroupId: z.string().optional(), - splmntAtchFileNm: z.string().optional(), - splmntAtchFileAtflId: z.string().optional(), - cmptnYn: z.string().optional(), }), ), privacyConsent: z.enum(["Y", "N"], { diff --git a/apps/as/src/pages/instl-sncn/lib/save-payload-utils.ts b/apps/as/src/pages/instl-sncn/lib/save-payload-utils.ts index f2d647aea..cd810c44b 100644 --- a/apps/as/src/pages/instl-sncn/lib/save-payload-utils.ts +++ b/apps/as/src/pages/instl-sncn/lib/save-payload-utils.ts @@ -8,6 +8,7 @@ import type { InstlSncnSplmntDmndSaveDto, ReviewStepCode, } from "@/entities/instl-sncn"; +import { instlSncnApplySaveSchema } from "@/entities/instl-sncn"; import { type SplmntDmndDialogConfirmPayload, toEsntlAtchFileSaveList } from "@/widgets/pbadms-sprt"; import type { ChecklistFormState } from "../model/view-types"; @@ -23,7 +24,6 @@ export function toBzScaleSaveDto(bizSclList: BizSclTreeDto[]): InstlSncnBzScaleS bscPl: node.bscPlanQty, budgetReflct: node.bgtRfltQty, thtiDsgn: node.tstmDesignQty, - diff: node.tstmDesignQty - node.bgtRfltQty, })); } @@ -46,13 +46,13 @@ export function buildSavePayload( ): InstlSncnApplySaveRequestDto { const { detDto, bizSclList, bizCstList, cklstResultList = [], esntlFileList } = data; - return { + return instlSncnApplySaveSchema.parse({ instlSncnMng: { ...detDto, prgrsSttsComCd }, bzScaleList: toBzScaleSaveDto(bizSclList), bizCstList: toBizCstSaveDto(bizCstList), cklstResultList: toCklstSaveDto(cklstResultList, checklistFormState, reviewStep), esntlAtchFileList: toEsntlAtchFileSaveList(esntlFileList), - }; + }); } export function buildTechReviewReplyPayload( @@ -64,12 +64,12 @@ export function buildTechReviewReplyPayload( reviewOpinionFormData?: ReviewOpinionFormData | null, opnrNm?: string, ): InstlSncnApplySaveRequestDto { - return { + return instlSncnApplySaveSchema.parse({ ...buildSavePayload(data, checklistFormState, reviewStep, prgrsSttsComCd), techReViewSaveCd, rvwStpCd: reviewStep, rvwOpnnList: toRvwOpnnSaveDto(data, reviewOpinionFormData, opnrNm), - }; + }); } export function buildSupplementReqPayload( @@ -91,10 +91,10 @@ export function buildSupplementReqPayload( cmptnYn: "N", })); - return { + return instlSncnApplySaveSchema.parse({ ...buildSavePayload(data, checklistFormState, "LOCAL", "SL"), splmntDmndList: [...existingItems, ...newItems], - }; + }); } export function toSplmntDmndSaveItem(item: InstlSncnSplmntDmndSaveDto): InstlSncnSplmntDmndSaveDto { diff --git a/apps/as/src/pages/instl-sncn/ui/instl-form-page.tsx b/apps/as/src/pages/instl-sncn/ui/instl-form-page.tsx index a52c9776d..d8510664f 100644 --- a/apps/as/src/pages/instl-sncn/ui/instl-form-page.tsx +++ b/apps/as/src/pages/instl-sncn/ui/instl-form-page.tsx @@ -12,7 +12,6 @@ import { useAlertStore, useUserStore } from "@/shared/lib"; import { SectionCollapsibleGroup, SectionCollapsibleToggle } from "@/shared/ui"; import { useEsntlAtchFileMngTree } from "@/entities/esntl"; import { - type InstlSncnApplySaveRequestDto, instlSncnKeys, type InstlSncnMngDetResponse, instlSncnService, @@ -31,12 +30,8 @@ import { } from "@/widgets/pbadms-sprt"; import { Button } from "@common/components"; -import { getCreateDefaultValues, mapDetailToFormData } from "../lib/form-data-mapper"; -import { - formatTaskSeComCdForApi, - type InstlSncnRegistFormData, - instlSncnRegistSchema, -} from "../lib/instl-sncn-regist-schema"; +import { buildFormPayload, getCreateDefaultValues, mapDetailToFormData } from "../lib/form-data-mapper"; +import { type InstlSncnRegistFormData, instlSncnRegistSchema } from "../lib/instl-sncn-regist-schema"; import { PROGRESS_STATUS_COLUMNS } from "../model/columns"; import { BasicInfoFormSection } from "./sections/basic-info-form-section"; @@ -72,47 +67,24 @@ function InstlFormPage({ mode, initialData, createDefaults }: InstlFormPageProps : getCreateDefaultValues(userInfo, createDefaults), }); - function buildFormPayload( - data: InstlSncnRegistFormData, - prgrsSttsComCd: "SV" | "ST" | "TE", - ): InstlSncnApplySaveRequestDto { - const { taskSeComCd: formTaskSeComCd, ...instlSncnMngRest } = data.instlSncnMng; - - return { - instlSncnMng: { - ...instlSncnMngRest, - instlSncnDocNo: isEditMode ? initialData?.detDto.instlSncnDocNo : undefined, - taskSeComCd: formatTaskSeComCdForApi(formTaskSeComCd), - prgrsSttsComCd, - }, - bzScaleList: data.bzScaleList, - bizCstList: data.bizCstList, - cklstResultList: data.cklstResultList.map((item) => ({ - ...item, - selected: item.selected, - })), - esntlAtchFileList: data.esntlAtchFileList, - splmntDmndList: data.splmntDmndList.map( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - ({ splmntAtchFileNm, splmntAtchFileAtflId, splmntDmndAtchFileNm, ...item }) => ({ - ...item, - ...(prgrsSttsComCd === "TE" ? { cmptnYn: "Y" } : null), - }), - ), - }; + function createFormPayload(data: InstlSncnRegistFormData, prgrsSttsComCd: "SV" | "ST" | "TE") { + return buildFormPayload(data, prgrsSttsComCd, { + isEditMode, + docNo: initialData?.detDto.instlSncnDocNo, + }); } async function submitForm( data: InstlSncnRegistFormData, prgrsSttsComCd: "SV" | "ST", ): Promise { - return instlSncnService.saveApply(buildFormPayload(data, prgrsSttsComCd)); + return instlSncnService.saveApply(createFormPayload(data, prgrsSttsComCd)); } async function submitSupplementForm(data: InstlSncnRegistFormData): Promise { const docNo = initialData?.detDto.instlSncnDocNo; if (!docNo) return undefined; - return instlSncnService.submitSupplement(docNo, buildFormPayload(data, "TE")); + return instlSncnService.submitSupplement(docNo, createFormPayload(data, "TE")); } async function onSplmntCmptn(data: InstlSncnRegistFormData) { diff --git a/apps/as/src/pages/sewer-bsc-plan/lib/payload-utils.ts b/apps/as/src/pages/sewer-bsc-plan/lib/payload-utils.ts index 07224c8ef..df63265a4 100644 --- a/apps/as/src/pages/sewer-bsc-plan/lib/payload-utils.ts +++ b/apps/as/src/pages/sewer-bsc-plan/lib/payload-utils.ts @@ -3,6 +3,7 @@ import type { SewerBscPlanDetResponseDto, SewerBscPlanSplmntDmndItem, } from "@/entities/sewer-bsc-plan"; +import { sewerBscPlanApplySaveSchema } from "@/entities/sewer-bsc-plan"; import { type SplmntDmndDialogConfirmPayload, toEsntlAtchFileSaveList } from "@/widgets/pbadms-sprt"; import type { ChecklistFormState, ReviewStepCode } from "../model/view-types"; @@ -26,7 +27,7 @@ export function buildSavePayload( const cklstResultRows = data.cklstResultRows ?? []; const esntlFileList = data.esntlFileList ?? []; - return { + return sewerBscPlanApplySaveSchema.parse({ sewerBscPlan: { sewerBscPlanDocNo: detDto.sewerBscPlanDocNo, admdstCd: detDto.admdstCd, @@ -99,7 +100,7 @@ export function buildSavePayload( })), cklstResultList: toCklstSaveDto(cklstResultRows, checklistFormState, reviewStep), esntlAtchFileList: toEsntlAtchFileSaveList(esntlFileList), - }; + }); } export function buildTechReviewReplyPayload( @@ -111,12 +112,12 @@ export function buildTechReviewReplyPayload( reviewOpinionFormData?: ReviewOpinionGetFormDataResult | null, opnrNm?: string, ): SewerBscPlanApplySaveRequestDto { - return { + return sewerBscPlanApplySaveSchema.parse({ ...buildSavePayload(data, checklistFormState, reviewStep, prgrsSttsComCd), techReViewSaveCd, rvwStpCd: reviewStep, rvwOpnnList: toRvwOpnnSaveDto(data, reviewOpinionFormData, opnrNm), - }; + }); } export function buildSupplementReqPayload( @@ -136,10 +137,10 @@ export function buildSupplementReqPayload( cmptnYn: "N", })); - return { + return sewerBscPlanApplySaveSchema.parse({ ...buildSavePayload(data, checklistFormState, "LOCAL", "SL"), splmntDmndList: [...existingItems, ...newItems], - }; + }); } export function toSplmntDmndSaveItem(item: SewerBscPlanSplmntDmndItem): SewerBscPlanSplmntDmndItem { diff --git a/apps/as/src/pages/sewer-bsc-plan/lib/sewer-bsc-plan-regist-schema.ts b/apps/as/src/pages/sewer-bsc-plan/lib/sewer-bsc-plan-regist-schema.ts index 416b1f401..d130d0673 100644 --- a/apps/as/src/pages/sewer-bsc-plan/lib/sewer-bsc-plan-regist-schema.ts +++ b/apps/as/src/pages/sewer-bsc-plan/lib/sewer-bsc-plan-regist-schema.ts @@ -77,7 +77,7 @@ export const sewerBscPlanRegistSchema = z.object({ cklstSn: z.number(), cklstArtclSn: z.number(), cklstRvwSn: z.number(), - selected: z.enum(["Y", "N"]).nullable(), + selected: z.enum(["Y", "N"]).nullish(), picRvwCn: z.string().nullable().optional(), }), ), diff --git a/apps/as/src/widgets/pbadms-sprt/lib/checklist-form-utils.ts b/apps/as/src/widgets/pbadms-sprt/lib/checklist-form-utils.ts index 52ad49f7a..bb4aae07d 100644 --- a/apps/as/src/widgets/pbadms-sprt/lib/checklist-form-utils.ts +++ b/apps/as/src/widgets/pbadms-sprt/lib/checklist-form-utils.ts @@ -22,7 +22,7 @@ interface CklstResultListItem { cklstArtclSn: number; cklstRvwSn: number; rvwStpComCd?: string | null; - selected: "Y" | "N" | null; + selected?: "Y" | "N" | null; picRvwCn?: string | null; } diff --git a/apps/as/src/widgets/pbadms-sprt/ui/checklist-form-section.tsx b/apps/as/src/widgets/pbadms-sprt/ui/checklist-form-section.tsx index 4b9866877..1e4c324bb 100644 --- a/apps/as/src/widgets/pbadms-sprt/ui/checklist-form-section.tsx +++ b/apps/as/src/widgets/pbadms-sprt/ui/checklist-form-section.tsx @@ -30,7 +30,7 @@ import { buildChecklistTabs, normalizeTaskSeComCdArray, syncCklstResultListFromTree, -} from "../lib/checklist-form-utils"; +} from "../lib/checklist-form-utils"; type FieldPrefix = "fnrsCnsltnMng" | "instlSncnMng" | "designCnstnMng" | "sewerBscPlan"; @@ -39,7 +39,7 @@ interface CklstResultListItem { cklstArtclSn: number; cklstRvwSn: number; rvwStpComCd: string; - selected: "Y" | "N" | null; + selected?: "Y" | "N" | null; picRvwCn?: string | null; } From 23ebf362442b0b6d4a37b63ff40a3af86033e771 Mon Sep 17 00:00:00 2001 From: bicochan Date: Mon, 21 Sep 2026 16:04:19 +0900 Subject: [PATCH 17/20] =?UTF-8?q?[as]=20feat:=20"@hookform/devtools"=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/as/package.json | 1 + .../design-cnstn/ui/design-form-page.tsx | 3 +- .../pages/fnrs-cnsltn/ui/fnrs-form-page.tsx | 3 +- .../pages/instl-sncn/ui/instl-form-page.tsx | 3 +- .../ui/sewer-bsc-plan-form-page.tsx | 3 +- apps/as/src/shared/ui/index.ts | 3 +- apps/as/src/shared/ui/rhf-devtool.tsx | 17 + pnpm-lock.yaml | 311 ++++++++++++++++-- 8 files changed, 308 insertions(+), 36 deletions(-) create mode 100644 apps/as/src/shared/ui/rhf-devtool.tsx diff --git a/apps/as/package.json b/apps/as/package.json index ed4016352..a90c4bdc1 100644 --- a/apps/as/package.json +++ b/apps/as/package.json @@ -36,6 +36,7 @@ }, "devDependencies": { "@eslint/eslintrc": "^3", + "@hookform/devtools": "^4.4.0", "@types/js-cookie": "^3.0.6", "eslint": "^9.0.0", "eslint-config-next": "15.3.8", diff --git a/apps/as/src/pages/design-cnstn/ui/design-form-page.tsx b/apps/as/src/pages/design-cnstn/ui/design-form-page.tsx index 7e0519db1..254a7a010 100644 --- a/apps/as/src/pages/design-cnstn/ui/design-form-page.tsx +++ b/apps/as/src/pages/design-cnstn/ui/design-form-page.tsx @@ -9,7 +9,7 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { useQueryClient } from "@tanstack/react-query"; import { useAlertStore, useUserStore } from "@/shared/lib"; -import { SectionCollapsibleGroup, SectionCollapsibleToggle } from "@/shared/ui"; +import { RhfDevTool, SectionCollapsibleGroup, SectionCollapsibleToggle } from "@/shared/ui"; import { designCnstnKeys, type DesignCnstnMngDetResponseDto, @@ -217,6 +217,7 @@ function DesignFormPage({ mode, initialData, createDefaults }: DesignFormPagePro + ); } diff --git a/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-form-page.tsx b/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-form-page.tsx index 28a9a0a51..d7af093a1 100644 --- a/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-form-page.tsx +++ b/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-form-page.tsx @@ -9,7 +9,7 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { useQueryClient } from "@tanstack/react-query"; import { useAlertStore, useUserStore } from "@/shared/lib"; -import { SectionCollapsibleGroup, SectionCollapsibleToggle } from "@/shared/ui"; +import { RhfDevTool, SectionCollapsibleGroup, SectionCollapsibleToggle } from "@/shared/ui"; import { useAcntgSeMngTree } from "@/entities/acntg"; import { useEsntlAtchFileMngTree } from "@/entities/esntl"; import { @@ -332,6 +332,7 @@ function FnrsFormPage({ mode, initialData, createDefaults }: FnrsFormPageProps) onClose={() => setIsPwrkCnsltnDocMngOpen(false)} /> ) : null} + ); } diff --git a/apps/as/src/pages/instl-sncn/ui/instl-form-page.tsx b/apps/as/src/pages/instl-sncn/ui/instl-form-page.tsx index d8510664f..131872a93 100644 --- a/apps/as/src/pages/instl-sncn/ui/instl-form-page.tsx +++ b/apps/as/src/pages/instl-sncn/ui/instl-form-page.tsx @@ -9,7 +9,7 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { useQueryClient } from "@tanstack/react-query"; import { useAlertStore, useUserStore } from "@/shared/lib"; -import { SectionCollapsibleGroup, SectionCollapsibleToggle } from "@/shared/ui"; +import { RhfDevTool, SectionCollapsibleGroup, SectionCollapsibleToggle } from "@/shared/ui"; import { useEsntlAtchFileMngTree } from "@/entities/esntl"; import { instlSncnKeys, @@ -272,6 +272,7 @@ function InstlFormPage({ mode, initialData, createDefaults }: InstlFormPageProps + ); } diff --git a/apps/as/src/pages/sewer-bsc-plan/ui/sewer-bsc-plan-form-page.tsx b/apps/as/src/pages/sewer-bsc-plan/ui/sewer-bsc-plan-form-page.tsx index 4c267b9a0..8c05521c3 100644 --- a/apps/as/src/pages/sewer-bsc-plan/ui/sewer-bsc-plan-form-page.tsx +++ b/apps/as/src/pages/sewer-bsc-plan/ui/sewer-bsc-plan-form-page.tsx @@ -9,7 +9,7 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { useQueryClient } from "@tanstack/react-query"; import { useAlertStore, useUserStore } from "@/shared/lib"; -import { SectionCollapsibleGroup, SectionCollapsibleToggle } from "@/shared/ui"; +import { RhfDevTool, SectionCollapsibleGroup, SectionCollapsibleToggle } from "@/shared/ui"; import { useAcntgSeMngTree } from "@/entities/acntg"; import { useEsntlAtchFileMngTree } from "@/entities/esntl"; import { @@ -319,6 +319,7 @@ function SewerBscPlanFormPage({ + ); } diff --git a/apps/as/src/shared/ui/index.ts b/apps/as/src/shared/ui/index.ts index 71cd9a481..89a554ff7 100644 --- a/apps/as/src/shared/ui/index.ts +++ b/apps/as/src/shared/ui/index.ts @@ -4,6 +4,7 @@ export type { FileAddButtonProps } from "./file-add-button"; export { FileAddButton } from "./file-add-button"; export { NoData } from "./no-data"; export { PageLayout } from "./page-layout"; +export { RhfDevTool } from "./rhf-devtool"; export { SectionCollapsible } from "./section-collapsible"; export { SectionCollapsibleGroup, @@ -12,4 +13,4 @@ export { export type { TextShimmerProps } from "./text-shimmer"; export { TEXT_SHIMMER_CLASS, TextShimmer } from "./text-shimmer"; export type { UploadedFileChipProps } from "./uploaded-file-chip"; -export { UploadedFileChip } from "./uploaded-file-chip"; +export { UploadedFileChip } from "./uploaded-file-chip"; \ No newline at end of file diff --git a/apps/as/src/shared/ui/rhf-devtool.tsx b/apps/as/src/shared/ui/rhf-devtool.tsx new file mode 100644 index 000000000..a318bdb79 --- /dev/null +++ b/apps/as/src/shared/ui/rhf-devtool.tsx @@ -0,0 +1,17 @@ +"use client"; + +import type { Control, FieldValues } from "react-hook-form"; +import dynamic from "next/dynamic"; + +const DevTool = dynamic(() => import("@hookform/devtools").then((mod) => mod.DevTool), { + ssr: false, +}); + +interface RhfDevToolProps { + control: Control; +} + +export function RhfDevTool({ control }: RhfDevToolProps) { + if (process.env.NODE_ENV !== "development") return null; + return } placement="top-left" />; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c05449b8a..b66b04b69 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -104,10 +104,10 @@ importers: devDependencies: eslint: specifier: ^9.0.0 - version: 9.39.4(jiti@1.21.7) + version: 9.39.4(jiti@2.6.1) eslint-config-next: specifier: 15.3.8 - version: 15.3.8(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) + version: 15.3.8(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) postcss: specifier: ^8.4.49 version: 8.5.8 @@ -202,18 +202,21 @@ importers: '@eslint/eslintrc': specifier: ^3 version: 3.3.5 + '@hookform/devtools': + specifier: ^4.4.0 + version: 4.4.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@types/js-cookie': specifier: ^3.0.6 version: 3.0.6 eslint: specifier: ^9.0.0 - version: 9.39.4(jiti@2.6.1) + version: 9.39.4(jiti@1.21.7) eslint-config-next: specifier: 15.3.8 - version: 15.3.8(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + version: 15.3.8(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) eslint-plugin-react-hooks: specifier: ^5.0.0 - version: 5.2.0(eslint@9.39.4(jiti@2.6.1)) + version: 5.2.0(eslint@9.39.4(jiti@1.21.7)) postcss: specifier: ^8.4.49 version: 8.5.8 @@ -282,7 +285,7 @@ importers: version: 4.1.3(react-hook-form@7.72.0(react@19.2.4)) '@minoru/react-dnd-treeview': specifier: 3.5.1-alpha.1 - version: 3.5.1-alpha.1(dnd-core@16.0.1)(react-dnd@16.0.1(@types/node@22.19.15)(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 3.5.1-alpha.1(@emotion/is-prop-valid@1.4.0)(dnd-core@16.0.1)(react-dnd@16.0.1(@types/node@22.19.15)(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@radix-ui/react-icons': specifier: ^1.3.2 version: 1.3.2(react@19.2.4) @@ -418,7 +421,7 @@ importers: version: 4.1.3(react-hook-form@7.72.0(react@19.2.4)) '@minoru/react-dnd-treeview': specifier: ^3.5.0 - version: 3.5.3(dnd-core@16.0.1)(react-dnd@16.0.1(@types/node@22.19.15)(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 3.5.3(@emotion/is-prop-valid@1.4.0)(dnd-core@16.0.1)(react-dnd@16.0.1(@types/node@22.19.15)(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@radix-ui/react-icons': specifier: ^1.3.2 version: 1.3.2(react@19.2.4) @@ -566,7 +569,7 @@ importers: version: 4.1.3(react-hook-form@7.72.0(react@19.2.4)) '@minoru/react-dnd-treeview': specifier: 3.5.1-alpha.1 - version: 3.5.1-alpha.1(dnd-core@16.0.1)(react-dnd@16.0.1(@types/node@22.19.15)(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 3.5.1-alpha.1(@emotion/is-prop-valid@1.4.0)(dnd-core@16.0.1)(react-dnd@16.0.1(@types/node@22.19.15)(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@radix-ui/react-icons': specifier: ^1.3.2 version: 1.3.2(react@19.2.4) @@ -696,7 +699,7 @@ importers: version: 4.1.3(react-hook-form@7.72.0(react@19.2.4)) '@minoru/react-dnd-treeview': specifier: ^3.5.0 - version: 3.5.3(dnd-core@16.0.1)(react-dnd@16.0.1(@types/node@22.19.15)(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 3.5.3(@emotion/is-prop-valid@1.4.0)(dnd-core@16.0.1)(react-dnd@16.0.1(@types/node@22.19.15)(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@radix-ui/react-label': specifier: ^2.1.2 version: 2.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -899,7 +902,7 @@ importers: version: 4.1.3(react-hook-form@7.72.0(react@19.2.4)) '@minoru/react-dnd-treeview': specifier: 3.5.1-alpha.1 - version: 3.5.1-alpha.1(dnd-core@16.0.1)(react-dnd@16.0.1(@types/node@22.19.15)(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 3.5.1-alpha.1(@emotion/is-prop-valid@1.4.0)(dnd-core@16.0.1)(react-dnd@16.0.1(@types/node@22.19.15)(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tailwindcss/vite': specifier: ^4.0.10 version: 4.2.2(vite@6.4.1(@types/node@22.19.15)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(yaml@2.8.3)) @@ -1002,7 +1005,7 @@ importers: version: 4.1.3(react-hook-form@7.72.0(react@19.2.4)) '@minoru/react-dnd-treeview': specifier: 3.5.1-alpha.1 - version: 3.5.1-alpha.1(dnd-core@16.0.1)(react-dnd@16.0.1(@types/node@22.19.15)(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 3.5.1-alpha.1(@emotion/is-prop-valid@1.4.0)(dnd-core@16.0.1)(react-dnd@16.0.1(@types/node@22.19.15)(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@radix-ui/react-label': specifier: ^2.1.2 version: 2.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -1174,7 +1177,7 @@ importers: version: 4.1.3(react-hook-form@7.72.0(react@19.2.4)) '@minoru/react-dnd-treeview': specifier: 3.5.1-alpha.1 - version: 3.5.1-alpha.1(dnd-core@16.0.1)(react-dnd@16.0.1(@types/node@22.19.15)(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 3.5.1-alpha.1(@emotion/is-prop-valid@1.4.0)(dnd-core@16.0.1)(react-dnd@16.0.1(@types/node@22.19.15)(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@radix-ui/react-icons': specifier: ^1.3.2 version: 1.3.2(react@19.2.4) @@ -1217,9 +1220,6 @@ importers: dayjs: specifier: ^1.11.13 version: 1.11.20 - decimal.js: - specifier: ^10.6.0 - version: 10.6.0 js-cookie: specifier: ^3.0.5 version: 3.0.5 @@ -1349,7 +1349,7 @@ importers: version: 4.1.3(react-hook-form@7.72.0(react@19.2.4)) '@minoru/react-dnd-treeview': specifier: 3.5.1-alpha.1 - version: 3.5.1-alpha.1(dnd-core@16.0.1)(react-dnd@16.0.1(@types/node@22.19.15)(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 3.5.1-alpha.1(@emotion/is-prop-valid@1.4.0)(dnd-core@16.0.1)(react-dnd@16.0.1(@types/node@22.19.15)(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@radix-ui/react-label': specifier: ^2.1.2 version: 2.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -1501,7 +1501,7 @@ importers: version: 4.1.3(react-hook-form@7.72.0(react@19.2.4)) '@minoru/react-dnd-treeview': specifier: 3.5.1-alpha.1 - version: 3.5.1-alpha.1(dnd-core@16.0.1)(react-dnd@16.0.1(@types/node@22.19.15)(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 3.5.1-alpha.1(@emotion/is-prop-valid@1.4.0)(dnd-core@16.0.1)(react-dnd@16.0.1(@types/node@22.19.15)(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@radix-ui/react-label': specifier: ^2.1.2 version: 2.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -1514,9 +1514,6 @@ importers: '@radix-ui/react-slot': specifier: ^1.1.2 version: 1.2.4(@types/react@19.2.14)(react@19.2.4) - '@tanstack/react-table': - specifier: ^8.21.2 - version: 8.21.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) axios: specifier: 1.8.1 version: 1.8.1 @@ -1691,7 +1688,7 @@ importers: version: 1.1.4 '@minoru/react-dnd-treeview': specifier: ^3.5.0 - version: 3.5.3(dnd-core@16.0.1)(react-dnd@16.0.1(@types/node@22.19.15)(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 3.5.3(@emotion/is-prop-valid@1.4.0)(dnd-core@16.0.1)(react-dnd@16.0.1(@types/node@22.19.15)(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@radix-ui/react-accordion': specifier: ^1.2.3 version: 1.2.12(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -2139,6 +2136,60 @@ packages: '@emnapi/wasi-threads@1.2.0': resolution: {integrity: sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==} + '@emotion/babel-plugin@11.13.5': + resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} + + '@emotion/cache@11.14.0': + resolution: {integrity: sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==} + + '@emotion/hash@0.9.2': + resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} + + '@emotion/is-prop-valid@1.4.0': + resolution: {integrity: sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==} + + '@emotion/memoize@0.9.0': + resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==} + + '@emotion/react@11.14.0': + resolution: {integrity: sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==} + peerDependencies: + '@types/react': '*' + react: ^19.2.1 + peerDependenciesMeta: + '@types/react': + optional: true + + '@emotion/serialize@1.3.3': + resolution: {integrity: sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==} + + '@emotion/sheet@1.4.0': + resolution: {integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==} + + '@emotion/styled@11.14.1': + resolution: {integrity: sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==} + peerDependencies: + '@emotion/react': ^11.0.0-rc.0 + '@types/react': '*' + react: ^19.2.1 + peerDependenciesMeta: + '@types/react': + optional: true + + '@emotion/unitless@0.10.0': + resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==} + + '@emotion/use-insertion-effect-with-fallbacks@1.2.0': + resolution: {integrity: sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==} + peerDependencies: + react: ^19.2.1 + + '@emotion/utils@1.4.2': + resolution: {integrity: sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==} + + '@emotion/weak-memoize@0.4.0': + resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==} + '@esbuild/aix-ppc64@0.21.5': resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} engines: {node: '>=12'} @@ -2677,6 +2728,12 @@ packages: peerDependencies: '@fullcalendar/core': ~6.1.20 + '@hookform/devtools@4.4.0': + resolution: {integrity: sha512-Mtlic+uigoYBPXlfvPBfiYYUZuyMrD3pTjDpVIhL6eCZTvQkHsKBSKeZCvXWUZr8fqrkzDg27N+ZuazLKq6Vmg==} + peerDependencies: + react: ^19.2.1 + react-dom: ^19.2.1 + '@hookform/resolvers@4.1.3': resolution: {integrity: sha512-Jsv6UOWYTrEFJ/01ZrnwVXs7KDvP8XIo115i++5PWvNkNvkrsTfGiLS6w+eJ57CYtUtDQalUWovCZDHFJ8u1VQ==} peerDependencies: @@ -4106,6 +4163,9 @@ packages: '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + '@types/lodash@4.17.25': + resolution: {integrity: sha512-+K1NIO8I+F9/wNulfVvu23QYd0Pe9/OCqRrim4NoYIf1VoEDL90Ve4ClzpyqBLc7NpGGWRvYNCKZ1BE/Jpf8dQ==} + '@types/mdx@2.0.13': resolution: {integrity: sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==} @@ -4115,6 +4175,9 @@ packages: '@types/node@22.19.15': resolution: {integrity: sha512-F0R/h2+dsy5wJAUe3tAU6oqa2qbWY5TpNfL/RGmo1y38hiyO1w3x2jPtt76wmuaJI4DQnOBu21cNXQ2STIUUWg==} + '@types/parse-json@4.0.2': + resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + '@types/react-dom@19.2.3': resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} peerDependencies: @@ -4554,6 +4617,10 @@ packages: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} + babel-plugin-macros@3.1.0: + resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} + engines: {node: '>=10', npm: '>=6'} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -4753,12 +4820,19 @@ packages: resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} engines: {node: ^14.18.0 || >=16.10.0} + convert-source-map@1.9.0: + resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + cosmiconfig@7.1.0: + resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} + engines: {node: '>=10'} + cosmiconfig@9.0.1: resolution: {integrity: sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==} engines: {node: '>=14'} @@ -4892,9 +4966,6 @@ packages: decimal.js-light@2.5.1: resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==} - decimal.js@10.6.0: - resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} - deep-eql@5.0.2: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} @@ -5254,6 +5325,7 @@ packages: eslint@9.39.4: resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true peerDependencies: jiti: '*' @@ -5358,6 +5430,9 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + find-root@1.1.0: + resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} + find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} @@ -5973,6 +6048,11 @@ packages: resolution: {integrity: sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==} engines: {node: '>=20.0.0'} + little-state-machine@4.8.1: + resolution: {integrity: sha512-liPHqaWMQ7rzZryQUDnbZ1Gclnnai3dIyaJ0nAgwZRXMzqbYrydrlCI0NDojRUbE5VYh5vu6hygEUZiH77nQkQ==} + peerDependencies: + react: ^19.2.1 + load-tsconfig@0.2.5: resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -6334,6 +6414,10 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + path-type@6.0.0: resolution: {integrity: sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==} engines: {node: '>=18'} @@ -6727,6 +6811,11 @@ packages: '@types/react': optional: true + react-simple-animate@3.5.3: + resolution: {integrity: sha512-Ob+SmB5J1tXDEZyOe2Hf950K4M8VaWBBmQ3cS2BUnTORqHjhK0iKG8fB+bo47ZL15t8d3g/Y0roiqH05UBjG7A==} + peerDependencies: + react-dom: ^19.2.1 + react-smooth@4.0.4: resolution: {integrity: sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==} peerDependencies: @@ -7127,6 +7216,9 @@ packages: babel-plugin-macros: optional: true + stylis@4.2.0: + resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} + sucrase@3.35.1: resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} engines: {node: '>=16 || 14 >=14.17'} @@ -7405,6 +7497,12 @@ packages: '@types/react': optional: true + use-deep-compare-effect@1.8.1: + resolution: {integrity: sha512-kbeNVZ9Zkc0RFGpfMN3MNfaKNvcLNyxOAAd9O4CBZ+kCBXXscn9s/4I+8ytUER4RDpEYs5+O6Rs4PqiZ+rHr5Q==} + engines: {node: '>=10', npm: '>=6'} + peerDependencies: + react: ^19.2.1 + use-sidecar@1.1.3: resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} engines: {node: '>=10'} @@ -7436,6 +7534,11 @@ packages: resolution: {integrity: sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew==} hasBin: true + uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). + hasBin: true + uuid@9.0.1: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). @@ -7639,6 +7742,10 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yaml@1.10.3: + resolution: {integrity: sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==} + engines: {node: '>= 6'} + yaml@2.8.3: resolution: {integrity: sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==} engines: {node: '>= 14.6'} @@ -7913,6 +8020,89 @@ snapshots: tslib: 2.8.1 optional: true + '@emotion/babel-plugin@11.13.5': + dependencies: + '@babel/helper-module-imports': 7.28.6 + '@babel/runtime': 7.29.2 + '@emotion/hash': 0.9.2 + '@emotion/memoize': 0.9.0 + '@emotion/serialize': 1.3.3 + babel-plugin-macros: 3.1.0 + convert-source-map: 1.9.0 + escape-string-regexp: 4.0.0 + find-root: 1.1.0 + source-map: 0.7.6 + stylis: 4.2.0 + transitivePeerDependencies: + - supports-color + + '@emotion/cache@11.14.0': + dependencies: + '@emotion/memoize': 0.9.0 + '@emotion/sheet': 1.4.0 + '@emotion/utils': 1.4.2 + '@emotion/weak-memoize': 0.4.0 + stylis: 4.2.0 + + '@emotion/hash@0.9.2': {} + + '@emotion/is-prop-valid@1.4.0': + dependencies: + '@emotion/memoize': 0.9.0 + + '@emotion/memoize@0.9.0': {} + + '@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4)': + dependencies: + '@babel/runtime': 7.29.2 + '@emotion/babel-plugin': 11.13.5 + '@emotion/cache': 11.14.0 + '@emotion/serialize': 1.3.3 + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.4) + '@emotion/utils': 1.4.2 + '@emotion/weak-memoize': 0.4.0 + hoist-non-react-statics: 3.3.2 + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + transitivePeerDependencies: + - supports-color + + '@emotion/serialize@1.3.3': + dependencies: + '@emotion/hash': 0.9.2 + '@emotion/memoize': 0.9.0 + '@emotion/unitless': 0.10.0 + '@emotion/utils': 1.4.2 + csstype: 3.2.3 + + '@emotion/sheet@1.4.0': {} + + '@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4)': + dependencies: + '@babel/runtime': 7.29.2 + '@emotion/babel-plugin': 11.13.5 + '@emotion/is-prop-valid': 1.4.0 + '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4) + '@emotion/serialize': 1.3.3 + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.4) + '@emotion/utils': 1.4.2 + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + transitivePeerDependencies: + - supports-color + + '@emotion/unitless@0.10.0': {} + + '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.2.4)': + dependencies: + react: 19.2.4 + + '@emotion/utils@1.4.2': {} + + '@emotion/weak-memoize@0.4.0': {} + '@esbuild/aix-ppc64@0.21.5': optional: true @@ -8253,6 +8443,22 @@ snapshots: '@fullcalendar/core': 6.1.20 '@fullcalendar/daygrid': 6.1.20(@fullcalendar/core@6.1.20) + '@hookform/devtools@4.4.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) + '@types/lodash': 4.17.25 + little-state-machine: 4.8.1(react@19.2.4) + lodash: 4.17.23 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-simple-animate: 3.5.3(react-dom@19.2.4(react@19.2.4)) + use-deep-compare-effect: 1.8.1(react@19.2.4) + uuid: 8.3.2 + transitivePeerDependencies: + - '@types/react' + - supports-color + '@hookform/resolvers@4.1.3(react-hook-form@7.72.0(react@19.2.4))': dependencies: '@standard-schema/utils': 0.3.0 @@ -8435,11 +8641,11 @@ snapshots: '@types/react': 19.2.14 react: 19.2.4 - '@minoru/react-dnd-treeview@3.5.1-alpha.1(dnd-core@16.0.1)(react-dnd@16.0.1(@types/node@22.19.15)(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@minoru/react-dnd-treeview@3.5.1-alpha.1(@emotion/is-prop-valid@1.4.0)(dnd-core@16.0.1)(react-dnd@16.0.1(@types/node@22.19.15)(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@juggle/resize-observer': 3.4.0 dnd-multi-backend: 8.1.2(dnd-core@16.0.1) - framer-motion: 11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + framer-motion: 11.18.2(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 react-dnd: 16.0.1(@types/node@22.19.15)(@types/react@19.2.14)(react@19.2.4) react-dnd-html5-backend: 16.0.1 @@ -8450,11 +8656,11 @@ snapshots: - '@emotion/is-prop-valid' - dnd-core - '@minoru/react-dnd-treeview@3.5.3(dnd-core@16.0.1)(react-dnd@16.0.1(@types/node@22.19.15)(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@minoru/react-dnd-treeview@3.5.3(@emotion/is-prop-valid@1.4.0)(dnd-core@16.0.1)(react-dnd@16.0.1(@types/node@22.19.15)(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@juggle/resize-observer': 3.4.0 dnd-multi-backend: 8.1.2(dnd-core@16.0.1) - framer-motion: 11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + framer-motion: 11.18.2(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 react-dnd: 16.0.1(@types/node@22.19.15)(@types/react@19.2.14)(react@19.2.4) react-dnd-html5-backend: 16.0.1 @@ -9637,6 +9843,8 @@ snapshots: '@types/json5@0.0.29': {} + '@types/lodash@4.17.25': {} + '@types/mdx@2.0.13': {} '@types/node@20.19.37': @@ -9647,6 +9855,8 @@ snapshots: dependencies: undici-types: 6.21.0 + '@types/parse-json@4.0.2': {} + '@types/react-dom@19.2.3(@types/react@19.2.14)': dependencies: '@types/react': 19.2.14 @@ -10301,6 +10511,12 @@ snapshots: axobject-query@4.1.0: {} + babel-plugin-macros@3.1.0: + dependencies: + '@babel/runtime': 7.29.2 + cosmiconfig: 7.1.0 + resolve: 1.22.11 + balanced-match@1.0.2: {} balanced-match@4.0.4: {} @@ -10495,10 +10711,20 @@ snapshots: consola@3.4.2: {} + convert-source-map@1.9.0: {} + convert-source-map@2.0.0: {} core-util-is@1.0.3: {} + cosmiconfig@7.1.0: + dependencies: + '@types/parse-json': 4.0.2 + import-fresh: 3.3.1 + parse-json: 5.2.0 + path-type: 4.0.0 + yaml: 1.10.3 + cosmiconfig@9.0.1(typescript@5.9.3): dependencies: env-paths: 2.2.1 @@ -10608,8 +10834,6 @@ snapshots: decimal.js-light@2.5.1: {} - decimal.js@10.6.0: {} - deep-eql@5.0.2: {} deep-is@0.1.4: {} @@ -11430,6 +11654,8 @@ snapshots: dependencies: to-regex-range: 5.0.1 + find-root@1.1.0: {} + find-up@4.1.0: dependencies: locate-path: 5.0.0 @@ -11470,12 +11696,13 @@ snapshots: fraction.js@5.3.4: {} - framer-motion@11.18.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + framer-motion@11.18.2(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: motion-dom: 11.18.1 motion-utils: 11.18.1 tslib: 2.8.1 optionalDependencies: + '@emotion/is-prop-valid': 1.4.0 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) @@ -11997,6 +12224,10 @@ snapshots: rfdc: 1.4.1 wrap-ansi: 9.0.2 + little-state-machine@4.8.1(react@19.2.4): + dependencies: + react: 19.2.4 + load-tsconfig@0.2.5: {} loader-runner@4.3.1: {} @@ -12345,6 +12576,8 @@ snapshots: lru-cache: 10.4.3 minipass: 7.1.3 + path-type@4.0.0: {} + path-type@6.0.0: {} path@0.12.7: @@ -12668,6 +12901,10 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 + react-simple-animate@3.5.3(react-dom@19.2.4(react@19.2.4)): + dependencies: + react-dom: 19.2.4(react@19.2.4) + react-smooth@4.0.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: fast-equals: 5.4.0 @@ -13185,6 +13422,8 @@ snapshots: client-only: 0.0.1 react: 19.2.4 + stylis@4.2.0: {} + sucrase@3.35.1: dependencies: '@jridgewell/gen-mapping': 0.3.13 @@ -13541,6 +13780,12 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 + use-deep-compare-effect@1.8.1(react@19.2.4): + dependencies: + '@babel/runtime': 7.29.2 + dequal: 2.0.3 + react: 19.2.4 + use-sidecar@1.1.3(@types/react@19.2.14)(react@19.2.4): dependencies: detect-node-es: 1.1.0 @@ -13573,6 +13818,8 @@ snapshots: uuid@14.0.1: {} + uuid@8.3.2: {} + uuid@9.0.1: {} victory-vendor@36.9.2: @@ -13781,6 +14028,8 @@ snapshots: yallist@3.1.1: {} + yaml@1.10.3: {} + yaml@2.8.3: {} yargs-parser@18.1.3: From 1674598480aa15e5a7d4798c6fa6d972317e42a5 Mon Sep 17 00:00:00 2001 From: bicochan Date: Mon, 21 Sep 2026 16:36:28 +0900 Subject: [PATCH 18/20] =?UTF-8?q?[as]=20design:=20RHFDevtool=20=EC=8A=A4?= =?UTF-8?q?=ED=83=80=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/components/floating-action-buttons.tsx | 19 +------------------ apps/as/src/shared/ui/rhf-devtool.tsx | 8 +++++++- 2 files changed, 8 insertions(+), 19 deletions(-) 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 b567a3b84..4076a83fa 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 @@ -419,19 +419,6 @@ function FloatingActionButtons({ } async function handleRqstTechRvwClick() { - if (prgrsSttsComCd === "LE") { - const { percent } = computeReviewStepChecklistProgress( - data.cklstResultList ?? [], - checklistFormState.results, - "ENV", - ); - - if (percent !== 100) { - alert("모든 체크리스트 항목을 체크해야 기술 검토 의뢰가 가능합니다."); - return; - } - } - const payload: FnrsExamineRequestDto = { prgrsSttsComCd: "FV", }; @@ -755,11 +742,7 @@ function FloatingActionButtons({ )} {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwRsltInq) && ( - )} diff --git a/apps/as/src/shared/ui/rhf-devtool.tsx b/apps/as/src/shared/ui/rhf-devtool.tsx index a318bdb79..0c9e69d9d 100644 --- a/apps/as/src/shared/ui/rhf-devtool.tsx +++ b/apps/as/src/shared/ui/rhf-devtool.tsx @@ -13,5 +13,11 @@ interface RhfDevToolProps { export function RhfDevTool({ control }: RhfDevToolProps) { if (process.env.NODE_ENV !== "development") return null; - return } placement="top-left" />; + return ( + } + placement="bottom-right" + styles={{ button: { right: "80px", bottom: "22px", scale: 2.5 } }} + /> + ); } From 17fdcd7d1fc61d180adaf51205339d26ec288d5d Mon Sep 17 00:00:00 2001 From: bicochan Date: Mon, 21 Sep 2026 16:56:46 +0900 Subject: [PATCH 19/20] =?UTF-8?q?fix:=20=EB=B9=8C=EB=93=9C=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/as/src/entities/design-cnstn/index.ts | 32 +++++++++---------- apps/as/src/entities/fnrs-cnsltn/index.ts | 36 +++++++++++----------- apps/as/src/entities/instl-sncn/index.ts | 34 ++++++++++---------- apps/as/src/shared/lib/use-data-table.tsx | 2 ++ apps/as/src/shared/lib/use-tus.ts | 2 ++ pnpm-lock.yaml | 21 ++++++++++--- 6 files changed, 71 insertions(+), 56 deletions(-) diff --git a/apps/as/src/entities/design-cnstn/index.ts b/apps/as/src/entities/design-cnstn/index.ts index b09702d6e..c9e3143de 100644 --- a/apps/as/src/entities/design-cnstn/index.ts +++ b/apps/as/src/entities/design-cnstn/index.ts @@ -37,6 +37,22 @@ export { useUpdateDesignCnstnMng, useUpdateDesignCnstnRvwOpnn, } from "./api/queries"; +export type { + BizCstItem, + BzScaleItem, + DesignCnstnApplySaveRequestDto, + DesignCnstnMngSaveRequestDto, + DesignCnstnRvwOpnnSaveRequestDto, + EsntlAtchFileItem, +} from "./model/design-cnstn-apply-payload-schema"; +export { + designCnstnApplySaveSchema, + designCnstnBizCstItemSchema, + designCnstnBzScaleItemSchema, + designCnstnEsntlAtchFileItemSchema, + designCnstnMngSaveSchema, + designCnstnRvwOpnnSaveSchema, +} from "./model/design-cnstn-apply-payload-schema"; export type { DesignCnstnBizCstId, DesignCnstnBizCstResponseDto, @@ -74,22 +90,6 @@ export type { ElaprDocPrgrsClientResponseDto, EsntlAtchFileMngTreeResponseDto, } from "./model/design-cnstn-mng-interface"; -export type { - BizCstItem, - BzScaleItem, - DesignCnstnApplySaveRequestDto, - DesignCnstnMngSaveRequestDto, - DesignCnstnRvwOpnnSaveRequestDto, - EsntlAtchFileItem, -} from "./model/design-cnstn-apply-payload-schema"; -export { - designCnstnApplySaveSchema, - designCnstnBizCstItemSchema, - designCnstnBzScaleItemSchema, - designCnstnEsntlAtchFileItemSchema, - designCnstnMngSaveSchema, - designCnstnRvwOpnnSaveSchema, -} from "./model/design-cnstn-apply-payload-schema"; export type { DesignCnstnRvwOpnnId, DesignCnstnRvwOpnnSearchDto, diff --git a/apps/as/src/entities/fnrs-cnsltn/index.ts b/apps/as/src/entities/fnrs-cnsltn/index.ts index 1fba74291..19941fb04 100644 --- a/apps/as/src/entities/fnrs-cnsltn/index.ts +++ b/apps/as/src/entities/fnrs-cnsltn/index.ts @@ -15,24 +15,6 @@ export { useTechReviewFnrsCnsltnMng, useUpdateFnrsCnsltnMng, } from "./api/queries"; -export type { - AtflMngClientResponseDto, - BizCstTreeDto, - BizSclTreeDto, - CklstRvwRsltTreeDto, - DocPrgrsUpdateRequestDto, - ElaprDocPrgrsClientResponseDto, - EsntlAtchFileMngTreeResponseDto, - FnrsCnsltnFileVrfcRsltResponseDto, - FnrsCnsltnMngDetResponseDto, - FnrsCnsltnMngResponseDto, - FnrsCnsltnMngSearchDto, - FnrsCnsltnMngService, - FnrsCnsltnMngUpdateRequestDto, - FnrsCnsltnRvwOpnnResponseDto, - FnrsCnsltnSplmntDmndResponseDto, - RagIndexingInfoDto, -} from "./model/fnrs-cnsltn-interface"; export type { BizCstItem, BzScaleItem, @@ -55,6 +37,24 @@ export { fnrsCnsltnSplmntDmndItemSchema, fnrsSharItemSchema, } from "./model/fnrs-cnsltn-apply-payload-schema"; +export type { + AtflMngClientResponseDto, + BizCstTreeDto, + BizSclTreeDto, + CklstRvwRsltTreeDto, + DocPrgrsUpdateRequestDto, + ElaprDocPrgrsClientResponseDto, + EsntlAtchFileMngTreeResponseDto, + FnrsCnsltnFileVrfcRsltResponseDto, + FnrsCnsltnMngDetResponseDto, + FnrsCnsltnMngResponseDto, + FnrsCnsltnMngSearchDto, + FnrsCnsltnMngService, + FnrsCnsltnMngUpdateRequestDto, + FnrsCnsltnRvwOpnnResponseDto, + FnrsCnsltnSplmntDmndResponseDto, + RagIndexingInfoDto, +} from "./model/fnrs-cnsltn-interface"; export type { EnvoActnReviewReqDto, FnrsExamineRequestDto, diff --git a/apps/as/src/entities/instl-sncn/index.ts b/apps/as/src/entities/instl-sncn/index.ts index ebeb5021b..5579b4c06 100644 --- a/apps/as/src/entities/instl-sncn/index.ts +++ b/apps/as/src/entities/instl-sncn/index.ts @@ -9,23 +9,6 @@ export { useInstlSncnSubmitSupplement, useInstlSncnTechReview, } from "./api/queries"; -export { - type AdstZoneResponseDto, - type AtflMngClientResponseDto, - type BizCstTreeDto, - type BizSclTreeDto, - type CklstRvwRsltTreeDto, - type DocPrgrsUpdateRequestDto, - type ElaprDocPrgrsClientResponseDto, - type EsntlAtchFileMngTreeResponseDto, - INSTL_SNCN_REGISTER_SELECTION_KEY, - type InstlSncnMngDetResponse, - type InstlSncnMngResponseDto, - type InstlSncnMngSearchParams, - type InstlSncnRvwOpnnResponseDto, - type InstlSncnSplmntDmndResponseDto, - type ReviewStepCode, -} from "./model/instl-sncn-interface"; export type { InstlSncnApplySaveRequestDto, InstlSncnBizCstSaveRequestDto, @@ -46,3 +29,20 @@ export { instlSncnRvwOpnnSaveSchema, instlSncnSplmntDmndItemSchema, } from "./model/instl-sncn-apply-payload-schema"; +export { + type AdstZoneResponseDto, + type AtflMngClientResponseDto, + type BizCstTreeDto, + type BizSclTreeDto, + type CklstRvwRsltTreeDto, + type DocPrgrsUpdateRequestDto, + type ElaprDocPrgrsClientResponseDto, + type EsntlAtchFileMngTreeResponseDto, + INSTL_SNCN_REGISTER_SELECTION_KEY, + type InstlSncnMngDetResponse, + type InstlSncnMngResponseDto, + type InstlSncnMngSearchParams, + type InstlSncnRvwOpnnResponseDto, + type InstlSncnSplmntDmndResponseDto, + type ReviewStepCode, +} from "./model/instl-sncn-interface"; diff --git a/apps/as/src/shared/lib/use-data-table.tsx b/apps/as/src/shared/lib/use-data-table.tsx index ef473f50d..df3b16f6e 100644 --- a/apps/as/src/shared/lib/use-data-table.tsx +++ b/apps/as/src/shared/lib/use-data-table.tsx @@ -1,3 +1,5 @@ +"use client"; + import type { HTMLAttributes } from "react"; import type { UseQueryResult } from "@tanstack/react-query"; diff --git a/apps/as/src/shared/lib/use-tus.ts b/apps/as/src/shared/lib/use-tus.ts index 1009b5adc..7a48cad6c 100644 --- a/apps/as/src/shared/lib/use-tus.ts +++ b/apps/as/src/shared/lib/use-tus.ts @@ -1,3 +1,5 @@ +"use client"; + import { useCallback, useState } from "react"; import { type Upload } from "tus-js-client"; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b66b04b69..95874cabc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -104,10 +104,10 @@ importers: devDependencies: eslint: specifier: ^9.0.0 - version: 9.39.4(jiti@2.6.1) + version: 9.39.4(jiti@1.21.7) eslint-config-next: specifier: 15.3.8 - version: 15.3.8(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + version: 15.3.8(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) postcss: specifier: ^8.4.49 version: 8.5.8 @@ -210,13 +210,13 @@ importers: version: 3.0.6 eslint: specifier: ^9.0.0 - version: 9.39.4(jiti@1.21.7) + version: 9.39.4(jiti@2.6.1) eslint-config-next: specifier: 15.3.8 - version: 15.3.8(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) + version: 15.3.8(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) eslint-plugin-react-hooks: specifier: ^5.0.0 - version: 5.2.0(eslint@9.39.4(jiti@1.21.7)) + version: 5.2.0(eslint@9.39.4(jiti@2.6.1)) postcss: specifier: ^8.4.49 version: 8.5.8 @@ -1220,6 +1220,9 @@ importers: dayjs: specifier: ^1.11.13 version: 1.11.20 + decimal.js: + specifier: ^10.6.0 + version: 10.6.0 js-cookie: specifier: ^3.0.5 version: 3.0.5 @@ -1514,6 +1517,9 @@ importers: '@radix-ui/react-slot': specifier: ^1.1.2 version: 1.2.4(@types/react@19.2.14)(react@19.2.4) + '@tanstack/react-table': + specifier: ^8.21.2 + version: 8.21.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) axios: specifier: 1.8.1 version: 1.8.1 @@ -4966,6 +4972,9 @@ packages: decimal.js-light@2.5.1: resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==} + decimal.js@10.6.0: + resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + deep-eql@5.0.2: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} @@ -10834,6 +10843,8 @@ snapshots: decimal.js-light@2.5.1: {} + decimal.js@10.6.0: {} + deep-eql@5.0.2: {} deep-is@0.1.4: {} From e60a8bed8bc27262ca80f1dae5efb73c878577fd Mon Sep 17 00:00:00 2001 From: bicochan Date: Mon, 21 Sep 2026 16:56:46 +0900 Subject: [PATCH 20/20] =?UTF-8?q?fix:=20=EB=B9=8C=EB=93=9C=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/as/src/entities/design-cnstn/index.ts | 32 +++++++++---------- apps/as/src/entities/fnrs-cnsltn/index.ts | 36 +++++++++++----------- apps/as/src/entities/instl-sncn/index.ts | 34 ++++++++++---------- apps/as/src/shared/lib/use-data-table.tsx | 2 ++ apps/as/src/shared/lib/use-tus.ts | 2 ++ pnpm-lock.yaml | 21 ++++++++++--- 6 files changed, 71 insertions(+), 56 deletions(-) diff --git a/apps/as/src/entities/design-cnstn/index.ts b/apps/as/src/entities/design-cnstn/index.ts index b09702d6e..c9e3143de 100644 --- a/apps/as/src/entities/design-cnstn/index.ts +++ b/apps/as/src/entities/design-cnstn/index.ts @@ -37,6 +37,22 @@ export { useUpdateDesignCnstnMng, useUpdateDesignCnstnRvwOpnn, } from "./api/queries"; +export type { + BizCstItem, + BzScaleItem, + DesignCnstnApplySaveRequestDto, + DesignCnstnMngSaveRequestDto, + DesignCnstnRvwOpnnSaveRequestDto, + EsntlAtchFileItem, +} from "./model/design-cnstn-apply-payload-schema"; +export { + designCnstnApplySaveSchema, + designCnstnBizCstItemSchema, + designCnstnBzScaleItemSchema, + designCnstnEsntlAtchFileItemSchema, + designCnstnMngSaveSchema, + designCnstnRvwOpnnSaveSchema, +} from "./model/design-cnstn-apply-payload-schema"; export type { DesignCnstnBizCstId, DesignCnstnBizCstResponseDto, @@ -74,22 +90,6 @@ export type { ElaprDocPrgrsClientResponseDto, EsntlAtchFileMngTreeResponseDto, } from "./model/design-cnstn-mng-interface"; -export type { - BizCstItem, - BzScaleItem, - DesignCnstnApplySaveRequestDto, - DesignCnstnMngSaveRequestDto, - DesignCnstnRvwOpnnSaveRequestDto, - EsntlAtchFileItem, -} from "./model/design-cnstn-apply-payload-schema"; -export { - designCnstnApplySaveSchema, - designCnstnBizCstItemSchema, - designCnstnBzScaleItemSchema, - designCnstnEsntlAtchFileItemSchema, - designCnstnMngSaveSchema, - designCnstnRvwOpnnSaveSchema, -} from "./model/design-cnstn-apply-payload-schema"; export type { DesignCnstnRvwOpnnId, DesignCnstnRvwOpnnSearchDto, diff --git a/apps/as/src/entities/fnrs-cnsltn/index.ts b/apps/as/src/entities/fnrs-cnsltn/index.ts index 1fba74291..19941fb04 100644 --- a/apps/as/src/entities/fnrs-cnsltn/index.ts +++ b/apps/as/src/entities/fnrs-cnsltn/index.ts @@ -15,24 +15,6 @@ export { useTechReviewFnrsCnsltnMng, useUpdateFnrsCnsltnMng, } from "./api/queries"; -export type { - AtflMngClientResponseDto, - BizCstTreeDto, - BizSclTreeDto, - CklstRvwRsltTreeDto, - DocPrgrsUpdateRequestDto, - ElaprDocPrgrsClientResponseDto, - EsntlAtchFileMngTreeResponseDto, - FnrsCnsltnFileVrfcRsltResponseDto, - FnrsCnsltnMngDetResponseDto, - FnrsCnsltnMngResponseDto, - FnrsCnsltnMngSearchDto, - FnrsCnsltnMngService, - FnrsCnsltnMngUpdateRequestDto, - FnrsCnsltnRvwOpnnResponseDto, - FnrsCnsltnSplmntDmndResponseDto, - RagIndexingInfoDto, -} from "./model/fnrs-cnsltn-interface"; export type { BizCstItem, BzScaleItem, @@ -55,6 +37,24 @@ export { fnrsCnsltnSplmntDmndItemSchema, fnrsSharItemSchema, } from "./model/fnrs-cnsltn-apply-payload-schema"; +export type { + AtflMngClientResponseDto, + BizCstTreeDto, + BizSclTreeDto, + CklstRvwRsltTreeDto, + DocPrgrsUpdateRequestDto, + ElaprDocPrgrsClientResponseDto, + EsntlAtchFileMngTreeResponseDto, + FnrsCnsltnFileVrfcRsltResponseDto, + FnrsCnsltnMngDetResponseDto, + FnrsCnsltnMngResponseDto, + FnrsCnsltnMngSearchDto, + FnrsCnsltnMngService, + FnrsCnsltnMngUpdateRequestDto, + FnrsCnsltnRvwOpnnResponseDto, + FnrsCnsltnSplmntDmndResponseDto, + RagIndexingInfoDto, +} from "./model/fnrs-cnsltn-interface"; export type { EnvoActnReviewReqDto, FnrsExamineRequestDto, diff --git a/apps/as/src/entities/instl-sncn/index.ts b/apps/as/src/entities/instl-sncn/index.ts index ebeb5021b..5579b4c06 100644 --- a/apps/as/src/entities/instl-sncn/index.ts +++ b/apps/as/src/entities/instl-sncn/index.ts @@ -9,23 +9,6 @@ export { useInstlSncnSubmitSupplement, useInstlSncnTechReview, } from "./api/queries"; -export { - type AdstZoneResponseDto, - type AtflMngClientResponseDto, - type BizCstTreeDto, - type BizSclTreeDto, - type CklstRvwRsltTreeDto, - type DocPrgrsUpdateRequestDto, - type ElaprDocPrgrsClientResponseDto, - type EsntlAtchFileMngTreeResponseDto, - INSTL_SNCN_REGISTER_SELECTION_KEY, - type InstlSncnMngDetResponse, - type InstlSncnMngResponseDto, - type InstlSncnMngSearchParams, - type InstlSncnRvwOpnnResponseDto, - type InstlSncnSplmntDmndResponseDto, - type ReviewStepCode, -} from "./model/instl-sncn-interface"; export type { InstlSncnApplySaveRequestDto, InstlSncnBizCstSaveRequestDto, @@ -46,3 +29,20 @@ export { instlSncnRvwOpnnSaveSchema, instlSncnSplmntDmndItemSchema, } from "./model/instl-sncn-apply-payload-schema"; +export { + type AdstZoneResponseDto, + type AtflMngClientResponseDto, + type BizCstTreeDto, + type BizSclTreeDto, + type CklstRvwRsltTreeDto, + type DocPrgrsUpdateRequestDto, + type ElaprDocPrgrsClientResponseDto, + type EsntlAtchFileMngTreeResponseDto, + INSTL_SNCN_REGISTER_SELECTION_KEY, + type InstlSncnMngDetResponse, + type InstlSncnMngResponseDto, + type InstlSncnMngSearchParams, + type InstlSncnRvwOpnnResponseDto, + type InstlSncnSplmntDmndResponseDto, + type ReviewStepCode, +} from "./model/instl-sncn-interface"; diff --git a/apps/as/src/shared/lib/use-data-table.tsx b/apps/as/src/shared/lib/use-data-table.tsx index ef473f50d..df3b16f6e 100644 --- a/apps/as/src/shared/lib/use-data-table.tsx +++ b/apps/as/src/shared/lib/use-data-table.tsx @@ -1,3 +1,5 @@ +"use client"; + import type { HTMLAttributes } from "react"; import type { UseQueryResult } from "@tanstack/react-query"; diff --git a/apps/as/src/shared/lib/use-tus.ts b/apps/as/src/shared/lib/use-tus.ts index 1009b5adc..7a48cad6c 100644 --- a/apps/as/src/shared/lib/use-tus.ts +++ b/apps/as/src/shared/lib/use-tus.ts @@ -1,3 +1,5 @@ +"use client"; + import { useCallback, useState } from "react"; import { type Upload } from "tus-js-client"; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b66b04b69..95874cabc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -104,10 +104,10 @@ importers: devDependencies: eslint: specifier: ^9.0.0 - version: 9.39.4(jiti@2.6.1) + version: 9.39.4(jiti@1.21.7) eslint-config-next: specifier: 15.3.8 - version: 15.3.8(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + version: 15.3.8(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) postcss: specifier: ^8.4.49 version: 8.5.8 @@ -210,13 +210,13 @@ importers: version: 3.0.6 eslint: specifier: ^9.0.0 - version: 9.39.4(jiti@1.21.7) + version: 9.39.4(jiti@2.6.1) eslint-config-next: specifier: 15.3.8 - version: 15.3.8(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) + version: 15.3.8(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) eslint-plugin-react-hooks: specifier: ^5.0.0 - version: 5.2.0(eslint@9.39.4(jiti@1.21.7)) + version: 5.2.0(eslint@9.39.4(jiti@2.6.1)) postcss: specifier: ^8.4.49 version: 8.5.8 @@ -1220,6 +1220,9 @@ importers: dayjs: specifier: ^1.11.13 version: 1.11.20 + decimal.js: + specifier: ^10.6.0 + version: 10.6.0 js-cookie: specifier: ^3.0.5 version: 3.0.5 @@ -1514,6 +1517,9 @@ importers: '@radix-ui/react-slot': specifier: ^1.1.2 version: 1.2.4(@types/react@19.2.14)(react@19.2.4) + '@tanstack/react-table': + specifier: ^8.21.2 + version: 8.21.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) axios: specifier: 1.8.1 version: 1.8.1 @@ -4966,6 +4972,9 @@ packages: decimal.js-light@2.5.1: resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==} + decimal.js@10.6.0: + resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + deep-eql@5.0.2: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} @@ -10834,6 +10843,8 @@ snapshots: decimal.js-light@2.5.1: {} + decimal.js@10.6.0: {} + deep-eql@5.0.2: {} deep-is@0.1.4: {}