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 new file mode 100644 index 000000000..e67a9a6c7 --- /dev/null +++ b/apps/as/src/entities/fnrs-cnsltn/api/fnrs-cnsltn-service.ts @@ -0,0 +1,86 @@ +import { client } from "@/shared/api"; +import { ENDPOINT } from "@/shared/config"; +import type { PageResponse } from "@/shared/model"; + +import type { + DocPrgrsUpdateRequestDto, + FnrsCnsltnApplySaveRequestDto, + FnrsCnsltnMngDetResponseDto, + FnrsCnsltnMngResponseDto, + FnrsCnsltnMngSaveRequestDto, + FnrsCnsltnMngSearchDto, + FnrsCnsltnMngService, + FnrsCnsltnMngUpdateRequestDto, +} from "../model/fnrs-cnsltn-interface"; + +const BASE = ENDPOINT.AS_SERVICE.FNRS_CNSLTN_MNG; + +async function findPage( + searchDto: FnrsCnsltnMngSearchDto, +): Promise> { + const response = await client.get>(BASE, { + params: searchDto, + }); + return response.data; +} + +async function findById(fnrsCnsltnDocNo: string): Promise { + const response = await client.get(`${BASE}/${fnrsCnsltnDocNo}`); + return response.data; +} + +async function save(body: FnrsCnsltnMngSaveRequestDto): Promise { + const response = await client.post(BASE, body); + return response.data; +} + +async function saveApply(body: FnrsCnsltnApplySaveRequestDto): Promise { + const response = await client.post(`${BASE}/save-apply`, body); + return response.data; +} + +async function update( + fnrsCnsltnDocNo: string, + body: FnrsCnsltnMngUpdateRequestDto, +): Promise { + const response = await client.put(`${BASE}/${fnrsCnsltnDocNo}`, body); + return response.data; +} + +async function techReview(id: string, body: FnrsCnsltnApplySaveRequestDto): Promise { + await client.post(`${BASE}/${id}/tech-review`, body); +} + +async function submitSupplement(id: string, body: FnrsCnsltnApplySaveRequestDto): Promise { + const response = await client.post(`${BASE}/${id}/submitsupplement`, body); + return response.data; +} + +async function submitReqSupplement( + id: string, + body: FnrsCnsltnApplySaveRequestDto, +): Promise { + const response = await client.post(`${BASE}/${id}/reqsupplement`, body); + return response.data; +} + +async function remove(fnrsCnsltnDocNo: string): Promise { + await client.delete(`${BASE}/${fnrsCnsltnDocNo}`); +} + +async function changePrgrsSttsComCd(body: DocPrgrsUpdateRequestDto): Promise { + await client.post(`${BASE}/doc/updatePrgrsStts`, body); +} + +export const fnrsCnsltnMngService = { + findPage, + findById, + save, + saveApply, + update, + techReview, + submitSupplement, + submitReqSupplement, + remove, + changePrgrsSttsComCd, +} satisfies FnrsCnsltnMngService; diff --git a/apps/as/src/entities/fnrs-cnsltn/api/queries.ts b/apps/as/src/entities/fnrs-cnsltn/api/queries.ts new file mode 100644 index 000000000..ac564f300 --- /dev/null +++ b/apps/as/src/entities/fnrs-cnsltn/api/queries.ts @@ -0,0 +1,131 @@ +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; + +import { ENDPOINT } from "@/shared/config"; + +import type { + DocPrgrsUpdateRequestDto, + FnrsCnsltnApplySaveRequestDto, + FnrsCnsltnMngSaveRequestDto, + FnrsCnsltnMngSearchDto, + FnrsCnsltnMngUpdateRequestDto, +} from "../model/fnrs-cnsltn-interface"; + +import { fnrsCnsltnMngService } from "./fnrs-cnsltn-service"; + +const fnrsCnsltnMngBaseKey = [ENDPOINT.AS_SERVICE.FNRS_CNSLTN_MNG] as const; + +export function useFnrsCnsltnMngPage(params: FnrsCnsltnMngSearchDto) { + return useQuery({ + queryKey: [...fnrsCnsltnMngBaseKey, "findPage", params], + queryFn: () => fnrsCnsltnMngService.findPage(params), + }); +} + +export function useFnrsCnsltnMng(fnrsCnsltnDocNo: string | null | undefined) { + return useQuery({ + queryKey: [...fnrsCnsltnMngBaseKey, "findById", fnrsCnsltnDocNo], + queryFn: () => fnrsCnsltnMngService.findById(fnrsCnsltnDocNo!), + enabled: Boolean(fnrsCnsltnDocNo), + }); +} + +export function useSaveFnrsCnsltnMng() { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: (body: FnrsCnsltnMngSaveRequestDto) => fnrsCnsltnMngService.save(body), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: fnrsCnsltnMngBaseKey }); + }, + }); +} + +export function useSaveApplyFnrsCnsltnMng() { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: (body: FnrsCnsltnApplySaveRequestDto) => fnrsCnsltnMngService.saveApply(body), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: fnrsCnsltnMngBaseKey }); + }, + }); +} + +export function useUpdateFnrsCnsltnMng() { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: ({ + fnrsCnsltnDocNo, + body, + }: { + fnrsCnsltnDocNo: string; + body: FnrsCnsltnMngUpdateRequestDto; + }) => fnrsCnsltnMngService.update(fnrsCnsltnDocNo, body), + onSuccess: (_data, { fnrsCnsltnDocNo }) => { + queryClient.invalidateQueries({ queryKey: fnrsCnsltnMngBaseKey }); + queryClient.invalidateQueries({ + queryKey: [...fnrsCnsltnMngBaseKey, "findById", fnrsCnsltnDocNo], + }); + }, + }); +} + +export function useTechReviewFnrsCnsltnMng() { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: ({ id, body }: { id: string; body: FnrsCnsltnApplySaveRequestDto }) => + fnrsCnsltnMngService.techReview(id, body), + onSuccess: (_data, { id }) => { + queryClient.invalidateQueries({ queryKey: fnrsCnsltnMngBaseKey }); + queryClient.invalidateQueries({ + queryKey: [...fnrsCnsltnMngBaseKey, "findById", id], + }); + }, + }); +} + +export function useSubmitSupplementFnrsCnsltnMng() { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: ({ id, body }: { id: string; body: FnrsCnsltnApplySaveRequestDto }) => + fnrsCnsltnMngService.submitSupplement(id, body), + onSuccess: (_data, { id }) => { + queryClient.invalidateQueries({ queryKey: fnrsCnsltnMngBaseKey }); + queryClient.invalidateQueries({ + queryKey: [...fnrsCnsltnMngBaseKey, "findById", id], + }); + }, + }); +} + +export function useSubmitReqSupplementFnrsCnsltnMng() { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: ({ id, body }: { id: string; body: FnrsCnsltnApplySaveRequestDto }) => + fnrsCnsltnMngService.submitReqSupplement(id, body), + onSuccess: (_data, { id }) => { + queryClient.invalidateQueries({ queryKey: fnrsCnsltnMngBaseKey }); + queryClient.invalidateQueries({ + queryKey: [...fnrsCnsltnMngBaseKey, "findById", id], + }); + }, + }); +} + +export function useDeleteFnrsCnsltnMng() { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: (fnrsCnsltnDocNo: string) => fnrsCnsltnMngService.remove(fnrsCnsltnDocNo), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: fnrsCnsltnMngBaseKey }); + }, + }); +} + +export function useChangePrgrsSttsComCd() { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: (body: DocPrgrsUpdateRequestDto) => fnrsCnsltnMngService.changePrgrsSttsComCd(body), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: fnrsCnsltnMngBaseKey }); + }, + }); +} diff --git a/apps/as/src/entities/fnrs-cnsltn/index.ts b/apps/as/src/entities/fnrs-cnsltn/index.ts new file mode 100644 index 000000000..ca54cbfe6 --- /dev/null +++ b/apps/as/src/entities/fnrs-cnsltn/index.ts @@ -0,0 +1,37 @@ +export { fnrsCnsltnMngService } from "./api/fnrs-cnsltn-service"; +export { + useChangePrgrsSttsComCd, + useDeleteFnrsCnsltnMng, + useFnrsCnsltnMng, + useFnrsCnsltnMngPage, + useSaveApplyFnrsCnsltnMng, + useSaveFnrsCnsltnMng, + useSubmitReqSupplementFnrsCnsltnMng, + useSubmitSupplementFnrsCnsltnMng, + useTechReviewFnrsCnsltnMng, + useUpdateFnrsCnsltnMng, +} from "./api/queries"; +export type { + AtflMngClientResponseDto, + BizCstItem, + BizCstTreeDto, + BizSclTreeDto, + BzScaleItem, + CklstResultItem, + CklstRvwRsltTreeDto, + DocPrgrsUpdateRequestDto, + ElaprDocPrgrsClientResponseDto, + EsntlAtchFileItem, + EsntlAtchFileMngTreeResponseDto, + FnrsCnsltnApplySaveRequestDto, + FnrsCnsltnMngDetResponseDto, + FnrsCnsltnMngResponseDto, + FnrsCnsltnMngSaveRequestDto, + FnrsCnsltnMngSearchDto, + FnrsCnsltnMngService, + FnrsCnsltnMngUpdateRequestDto, + FnrsCnsltnRvwOpnnResponseDto, + FnrsCnsltnRvwOpnnSaveRequestDto, + FnrsCnsltnSplmntDmndItem, + FnrsCnsltnSplmntDmndResponseDto, +} from "./model/fnrs-cnsltn-interface"; 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 new file mode 100644 index 000000000..6dc5da4f4 --- /dev/null +++ b/apps/as/src/entities/fnrs-cnsltn/model/fnrs-cnsltn-interface.ts @@ -0,0 +1,277 @@ +import type { PageableParams, PageResponse } from "@/shared/model"; + +/** 백엔드 FnrsCnsltnMngResponseDto */ +export interface FnrsCnsltnMngResponseDto { + fnrsCnsltnDocNo: string; + admdstCd?: string; + envoSeComCd?: string; + envoSeCdNm?: string; + taskSeComCd?: string; + taskSeCdNm?: 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; + prgrsSttsComCd?: string; + prgrsSttsCdNm?: string; + regDt?: string; + rgtr?: string; + rgtrNm?: string; + mdfcnDt?: string; + sido?: string; + gugun?: string; +} + +/** 백엔드 FnrsCnsltnMngSearchDto + Pageable */ +export interface FnrsCnsltnMngSearchDto extends PageableParams { + 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; + prgrsSttsComCd?: string; +} + +/** 백엔드 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; + prgrsSttsComCd?: string; +} + +/** 백엔드 FnrsCnsltnMngUpdateRequestDto */ +export interface FnrsCnsltnMngUpdateRequestDto { + 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; + prgrsSttsComCd?: string; +} + +/** 백엔드 FnrsCnsltnMngDetResponseDto */ +export interface FnrsCnsltnMngDetResponseDto { + detDto?: FnrsCnsltnMngResponseDto; + bizSclList?: BizSclTreeDto[]; + bizCstList?: BizCstTreeDto[]; + cklstResultList?: CklstRvwRsltTreeDto[]; + esntlFileList?: EsntlAtchFileMngTreeResponseDto[]; + etcFileList?: AtflMngClientResponseDto[]; + rvwList?: FnrsCnsltnRvwOpnnResponseDto[]; + splmntDmndList?: FnrsCnsltnSplmntDmndResponseDto[]; + elaprDocPrgrsList?: ElaprDocPrgrsClientResponseDto[]; +} + +/** 백엔드 FnrsCnsltnApplySaveRequestDto */ +export interface FnrsCnsltnApplySaveRequestDto { + techReViewSaveCd?: string; + rvwStpCd?: string; + fnrsCnsltnMng: FnrsCnsltnMngSaveRequestDto; + bzScaleList?: BzScaleItem[]; + bizCstList?: BizCstItem[]; + cklstResultList?: CklstResultItem[]; + cklstResultMap?: Record; + esntlAtchFileList?: EsntlAtchFileItem[]; + rvwOpnnList?: FnrsCnsltnRvwOpnnSaveRequestDto[]; + splmntDmndList?: FnrsCnsltnSplmntDmndItem[]; +} + +/** 백엔드 DocPrgrsUpdateRequestDto */ +export interface DocPrgrsUpdateRequestDto { + docNo?: string; + prgrsSttsComCd?: string; +} + +export interface BzScaleItem { + cnstpSeCd?: string; + bscPl?: number; + budgetReflct?: number; + thtiDsgn?: number; +} + +export interface BizCstItem { + acntgSeCd?: string; + bscPlanAmt?: number; + bgtRfltAmt?: number; + tstmDesignAmt?: number; +} + +export interface CklstResultItem { + cklstRvwSn?: number; + cklstArtclSn?: number; + cklstSn?: number; + rvwStpComCd: string; + selected?: string; + picRvwCn?: string; +} + +export interface EsntlAtchFileItem { + esntlAtchFileId?: string; + atchFileGroupId?: string; +} + +export interface FnrsCnsltnSplmntDmndItem { + splmntDmndSn?: number; + splmntArtclComCd?: string; + splmntDmndCn?: string; + splmntDmndDt?: string; + splmntDmndAtchFileGroupId?: string; + splmntCn?: string; + splmntPicNm?: string; + splmntCmptnDt?: string; + splmntAtchFileGroupId?: string; + cmptnYn?: string; +} + +export interface BizSclTreeDto { + cnstpSeCd?: string; + cnstpSeNm?: string; + bscPl?: number; + budgetReflct?: number; + thtiDsgn?: number; +} + +export interface BizCstTreeDto { + acntgSeCd?: string; + acntgSeNm?: string; + bscPlanAmt?: number; + bgtRfltAmt?: number; + tstmDesignAmt?: number; +} + +export interface CklstRvwRsltTreeDto { + cklstRvwSn?: number; + cklstArtclSn?: number; + cklstSn?: number; + rvwStpComCd?: string; + selected?: string; + picRvwCn?: string; + cklstNm?: string; + cklstArtclNm?: string; +} + +export interface EsntlAtchFileMngTreeResponseDto { + esntlAtchFileId?: string; + atchFileGroupId?: string; + esntlAtchFileNm?: string; + esntlAtchYn?: string; +} + +export interface AtflMngClientResponseDto { + atflId?: string; + orgnlFileNm?: string; + atflFlieSz?: number; + atflType?: string; + dwnldNocs?: number; + regDt?: string; +} + +export interface FnrsCnsltnRvwOpnnResponseDto { + fnrsCnsltnRvwOpnnSn?: number; + fnrsCnsltnDocNo?: string; + rvwStpComCd?: string; + rvwOpnn?: string; + rvwOpnnDt?: string; + rgtr?: string; + rgtrNm?: string; +} + +export interface FnrsCnsltnRvwOpnnSaveRequestDto { + fnrsCnsltnDocNo?: string; + rvwStpComCd?: string; + rvwOpnn?: string; +} + +export interface FnrsCnsltnSplmntDmndResponseDto { + splmntDmndSn?: number; + fnrsCnsltnDocNo?: string; + splmntArtclComCd?: string; + splmntDmndCn?: string; + splmntDmndDt?: string; + splmntDmndAtchFileGroupId?: string; + splmntCn?: string; + splmntPicNm?: string; + splmntCmptnDt?: string; + splmntAtchFileGroupId?: string; + cmptnYn?: string; +} + +export interface ElaprDocPrgrsClientResponseDto { + elaprDmndNo?: string; + elaprAplnNo?: string; + docNo?: string; + docPrgrsSn?: number; + prgrsSttsComCd?: string; + prgrsSttsCdNm?: string; + aprvrNm?: string; + aprvDt?: string; +} + +/** Controller public 메서드명·시그니처와 동일 */ +export interface FnrsCnsltnMngService { + findPage(searchDto: FnrsCnsltnMngSearchDto): Promise>; + findById(fnrsCnsltnDocNo: string): Promise; + save(body: FnrsCnsltnMngSaveRequestDto): Promise; + saveApply(body: FnrsCnsltnApplySaveRequestDto): Promise; + update(fnrsCnsltnDocNo: string, body: FnrsCnsltnMngUpdateRequestDto): Promise; + techReview(id: string, body: FnrsCnsltnApplySaveRequestDto): Promise; + submitSupplement(id: string, body: FnrsCnsltnApplySaveRequestDto): Promise; + submitReqSupplement(id: string, body: FnrsCnsltnApplySaveRequestDto): Promise; + remove(fnrsCnsltnDocNo: string): Promise; + changePrgrsSttsComCd(body: DocPrgrsUpdateRequestDto): Promise; +} diff --git a/apps/as/src/pages/instl-sncn/ui/components/progress-step-indicator.tsx b/apps/as/src/pages/instl-sncn/ui/components/progress-step-indicator.tsx deleted file mode 100644 index e3cff5d35..000000000 --- a/apps/as/src/pages/instl-sncn/ui/components/progress-step-indicator.tsx +++ /dev/null @@ -1,111 +0,0 @@ -"use client"; - -import { Fragment } from "react"; - -import { Badge } from "@common/components"; - -interface ProgressStepIndicatorProps { - prgrsSttsComCd: string; - prgrsSttsCdNm: string; -} - -const MAIN_STEP_LABELS = { - save: "저장", - apply: "신청완료", - techReview: "기술검토", - reply: "검토결과 회신", -} as const; - -const TECH_REVIEW_STATUS_CODES = new Set(["LE", "ER", "EE", "TE", "TS", "TR", "TP"]); - -type BadgeState = "completed" | "current" | "pending" | "action"; - -interface ProgressBadge { - label: string; - state: BadgeState; -} - -function buildProgressBadges(prgrsSttsComCd: string, prgrsSttsCdNm: string): ProgressBadge[] { - const techReviewLabel = prgrsSttsCdNm || MAIN_STEP_LABELS.techReview; - const replyLabel = prgrsSttsCdNm || MAIN_STEP_LABELS.reply; - - if (prgrsSttsComCd === "SV") { - return [ - { label: MAIN_STEP_LABELS.save, state: "current" }, - { label: MAIN_STEP_LABELS.apply, state: "pending" }, - { label: MAIN_STEP_LABELS.techReview, state: "pending" }, - { label: MAIN_STEP_LABELS.reply, state: "pending" }, - ]; - } - - if (prgrsSttsComCd === "ST") { - return [ - { label: MAIN_STEP_LABELS.save, state: "completed" }, - { label: MAIN_STEP_LABELS.apply, state: "current" }, - { label: MAIN_STEP_LABELS.techReview, state: "pending" }, - { label: MAIN_STEP_LABELS.reply, state: "pending" }, - ]; - } - - if (TECH_REVIEW_STATUS_CODES.has(prgrsSttsComCd)) { - return [ - { label: MAIN_STEP_LABELS.save, state: "completed" }, - { label: MAIN_STEP_LABELS.apply, state: "completed" }, - { label: techReviewLabel, state: "action" }, - { label: MAIN_STEP_LABELS.reply, state: "pending" }, - ]; - } - - if (prgrsSttsComCd === "EP") { - return [ - { label: MAIN_STEP_LABELS.save, state: "completed" }, - { label: MAIN_STEP_LABELS.apply, state: "completed" }, - { label: MAIN_STEP_LABELS.techReview, state: "completed" }, - { label: replyLabel, state: "action" }, - ]; - } - - if (prgrsSttsComCd === "TA" || prgrsSttsComCd === "TB") { - return [ - { label: MAIN_STEP_LABELS.save, state: "completed" }, - { label: MAIN_STEP_LABELS.apply, state: "completed" }, - { label: MAIN_STEP_LABELS.techReview, state: "completed" }, - { label: MAIN_STEP_LABELS.reply, state: "completed" }, - ]; - } - - return [{ label: prgrsSttsCdNm || prgrsSttsComCd || "-", state: "current" }]; -} - -function getBadgeColor(state: BadgeState) { - switch (state) { - case "completed": - return "green"; - case "current": - return "blue"; - case "pending": - return "lightGray"; - case "action": - return "orange"; - } -} - -function ProgressStepIndicator({ prgrsSttsComCd, prgrsSttsCdNm }: ProgressStepIndicatorProps) { - const badges = buildProgressBadges(prgrsSttsComCd, prgrsSttsCdNm); - - return ( -
-

진행 단계

-
- {badges.map((badge, index) => ( - - {index > 0 && >} - {badge.label} - - ))} -
-
- ); -} - -export { ProgressStepIndicator }; diff --git a/apps/as/src/shared/config/api.ts b/apps/as/src/shared/config/api.ts index 784af3f15..a0545215d 100644 --- a/apps/as/src/shared/config/api.ts +++ b/apps/as/src/shared/config/api.ts @@ -15,6 +15,7 @@ export const ENDPOINT = { CKLST_ARTCL: "/as-service/api/v1/cklst-artcl", CKLST_RVW: "/as-service/api/v1/cklst-rvw", ADSTDSTR: "/as-service/api/v1/adstdstr", + FNRS_CNSLTN_MNG: "/as-service/api/v1/fnrs-cnsltn-mng", }, USER_SERVICE: { LOGIN: "/user-service/login",