From b38be38169201272e86a8eccf2c96aa7ae30107a Mon Sep 17 00:00:00 2001 From: bicochan Date: Mon, 7 Sep 2026 17:25:40 +0900 Subject: [PATCH] =?UTF-8?q?[as]=20feat:=20AI=20=EC=9E=90=EB=8F=99=20?= =?UTF-8?q?=EC=A7=84=ED=96=89=20=EB=8B=A8=EA=B3=84=20=EB=8C=80=EA=B8=B0=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=20=ED=85=8D=EC=8A=A4=ED=8A=B8=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/fnrs-cnsltn/lib/ai-pending-utils.ts | 21 ++ .../ui/components/floating-action-buttons.tsx | 246 +++++++++--------- .../pages/fnrs-cnsltn/ui/fnrs-view-page.tsx | 14 +- .../shared/ui/section-collapsible-group.tsx | 2 +- 4 files changed, 162 insertions(+), 121 deletions(-) create mode 100644 apps/as/src/pages/fnrs-cnsltn/lib/ai-pending-utils.ts 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 new file mode 100644 index 000000000..c310dbf16 --- /dev/null +++ b/apps/as/src/pages/fnrs-cnsltn/lib/ai-pending-utils.ts @@ -0,0 +1,21 @@ +const AI_PENDING_STATUS_CODES = ["FV", "AC", "AV"] as const; + +type AiPendingStatusCode = (typeof AI_PENDING_STATUS_CODES)[number]; + +const AI_PENDING_MESSAGES: Record = { + FV: "파일 검증이 진행 중입니다", + AC: "실무협의서 초안 생성이 진행 중입니다", + AV: "금액 검증이 진행 중입니다", +}; + +function isAiPendingStatus(prgrsSttsComCd: string): boolean { + return AI_PENDING_STATUS_CODES.includes(prgrsSttsComCd as AiPendingStatusCode); +} + +function getAiPendingMessage(prgrsSttsComCd: string): string { + if (!isAiPendingStatus(prgrsSttsComCd)) return ""; + return AI_PENDING_MESSAGES[prgrsSttsComCd as AiPendingStatusCode]; +} + +export { AI_PENDING_STATUS_CODES, getAiPendingMessage, isAiPendingStatus }; +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 81fce4fc4..d8283220e 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 @@ -57,6 +57,7 @@ interface FloatingActionButtonsProps { checklistFormState: ChecklistFormState; techReviewOpinionRef?: React.RefObject; opnrNm?: string; + isAiPending?: boolean; } type ActiveDialog = "elaprTmplt" | "rjct" | "dmndSplmnt" | "elaprApproval" | null; @@ -72,6 +73,7 @@ function FloatingActionButtons({ checklistFormState, techReviewOpinionRef, opnrNm, + isAiPending = false, }: FloatingActionButtonsProps) { const router = useRouter(); const { confirm } = useConfirm(); @@ -402,130 +404,138 @@ 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.fnrsCnsltnAncmnt) && ( - - )} - {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.rvwRply) && ( - - )} - {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rqstTechRvw) && ( - - )} - {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.fileVrfc) && ( - - )} - {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.dsgntRvwr) && ( - - )} - {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocCrt) && ( - - )} - {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng) && ( - - )} - {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwStrg) && ( - - )} - {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwCmptn) && ( - - )} - {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.dmndSplmnt) && ( - - )} - {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.atrzAprv) && ( - - )} - {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.atrzRply) && ( - + {!isAiPending && ( + <> + {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.fnrsCnsltnAncmnt) && ( + + )} + {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.rvwRply) && ( + + )} + {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rqstTechRvw) && ( + + )} + {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.fileVrfc) && ( + + )} + {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.dsgntRvwr) && ( + + )} + {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocCrt) && ( + + )} + {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng) && ( + + )} + {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwStrg) && ( + + )} + {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwCmptn) && ( + + )} + {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.dmndSplmnt) && ( + + )} + {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.atrzAprv) && ( + + )} + {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.atrzRply) && ( + + )} + )} - setActiveDialog(null)} - docSeComCd={docSeComCd} - onConfirm={handleElaprTmpltConfirm} - /> + {!isAiPending && ( + <> + setActiveDialog(null)} + docSeComCd={docSeComCd} + onConfirm={handleElaprTmpltConfirm} + /> - setActiveDialog(null)} - isSubmitting={isProcessing} - onConfirm={handleDmndSplmntConfirm} - /> + setActiveDialog(null)} + isSubmitting={isProcessing} + onConfirm={handleDmndSplmntConfirm} + /> - setActiveDialog(open ? "elaprApproval" : null)} - elaprDocNo={data.detDto?.fnrsCnsltnDocNo ?? fnrsCnsltnDocNo} - currentUserUuid={userInfo?.userUnqId ?? ""} - onSuccess={() => { - queryClient.invalidateQueries({ - queryKey: fnrsCnsltnKeys.detail(fnrsCnsltnDocNo), - }); - }} - /> + setActiveDialog(open ? "elaprApproval" : null)} + elaprDocNo={data.detDto?.fnrsCnsltnDocNo ?? fnrsCnsltnDocNo} + currentUserUuid={userInfo?.userUnqId ?? ""} + onSuccess={() => { + queryClient.invalidateQueries({ + queryKey: fnrsCnsltnKeys.detail(fnrsCnsltnDocNo), + }); + }} + /> + + )} ); } diff --git a/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-view-page.tsx b/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-view-page.tsx index bb7b22549..8d64073d4 100644 --- a/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-view-page.tsx +++ b/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-view-page.tsx @@ -3,7 +3,7 @@ import { useMemo, useRef } from "react"; import { useUserStore } from "@/shared/lib"; -import { SectionCollapsibleGroup, SectionCollapsibleToggle } from "@/shared/ui"; +import { SectionCollapsibleGroup, SectionCollapsibleToggle, TextShimmer } from "@/shared/ui"; import { ElaprDocPrgrsStatus } from "@/entities/elapr"; import { useFnrsCnsltnMng } from "@/entities/fnrs-cnsltn"; import { useRvwMnpwMngLoginUserList } from "@/entities/rvw-mnpw"; @@ -14,6 +14,7 @@ import { } from "@/widgets/pbadms-sprt"; import { Skeleton } from "@common/components"; +import { getAiPendingMessage, isAiPendingStatus } from "../lib/ai-pending-utils"; import { needsRoleUser01AtrzResolve } from "../lib/button-config"; import { getEditableReviewStep } from "../lib/review-step-utils"; import { EMPTY_CKLST_RESULT_LIST, useChecklistFormState } from "../lib/use-checklist-form-state"; @@ -93,11 +94,19 @@ function FnrsViewPage({ id }: FnrsViewPageProps) { userInfo?.dtlInstCd, detDto.prgrsSttsComCd || "", ); + const isAiPending = isAiPendingStatus(detDto.prgrsSttsComCd || ""); return (
- +
+ + {isAiPending && ( + + {getAiPendingMessage(detDto.prgrsSttsComCd || "")} + + )} +
diff --git a/apps/as/src/shared/ui/section-collapsible-group.tsx b/apps/as/src/shared/ui/section-collapsible-group.tsx index 88828e335..6e233f9e9 100644 --- a/apps/as/src/shared/ui/section-collapsible-group.tsx +++ b/apps/as/src/shared/ui/section-collapsible-group.tsx @@ -59,7 +59,7 @@ function SectionCollapsibleToggle() { const { batchOpen, expandAll, collapseAll } = group; return ( -
+