[as] feat: AI 수동 검증 버튼 추가

This commit is contained in:
2026-09-21 13:34:26 +09:00
parent 5fec5d5239
commit bd20a499d3
11 changed files with 359 additions and 33 deletions
@@ -0,0 +1,24 @@
import { client } from "@/shared/api";
import { ENDPOINT } from "@/shared/config";
import type {
AiAutoPrcsLatestResponseDto,
AiAutoPrcsMngService,
} from "../model/ai-auto-prcs-mng-interface";
const BASE = ENDPOINT.AS_SERVICE.AI_AUTO_PRCS_MNG;
async function findLatestPerAutoSeByFnrsDocNo(
fnrsCnsltnDocNo: string,
atmtnSeComCd?: string,
): Promise<AiAutoPrcsLatestResponseDto[]> {
const response = await client.get<AiAutoPrcsLatestResponseDto[]>(
`${BASE}/fnrs/${fnrsCnsltnDocNo}/latest`,
{ params: atmtnSeComCd ? { atmtnSeComCd } : undefined },
);
return response.data;
}
export const aiAutoPrcsMngService = {
findLatestPerAutoSeByFnrsDocNo,
} satisfies AiAutoPrcsMngService;
@@ -0,0 +1,30 @@
import { useQuery } from "@tanstack/react-query";
import { ENDPOINT } from "@/shared/config";
import { aiAutoPrcsMngService } from "./ai-auto-prcs-mng-service";
export const aiAutoPrcsMngKeys = {
all: [ENDPOINT.AS_SERVICE.AI_AUTO_PRCS_MNG] as const,
latest: (fnrsCnsltnDocNo: string, atmtnSeComCd?: string) =>
[...aiAutoPrcsMngKeys.all, "latest", fnrsCnsltnDocNo, atmtnSeComCd ?? "all"] as const,
};
interface UseAiAutoPrcsLatestOptions {
enabled?: boolean;
atmtnSeComCd?: string;
}
export function useAiAutoPrcsLatest(
fnrsCnsltnDocNo: string | null | undefined,
options: UseAiAutoPrcsLatestOptions = {},
) {
const { enabled = true, atmtnSeComCd } = options;
return useQuery({
queryKey: aiAutoPrcsMngKeys.latest(fnrsCnsltnDocNo!, atmtnSeComCd),
queryFn: () =>
aiAutoPrcsMngService.findLatestPerAutoSeByFnrsDocNo(fnrsCnsltnDocNo!, atmtnSeComCd),
enabled: Boolean(fnrsCnsltnDocNo) && enabled,
});
}
@@ -0,0 +1,8 @@
export { aiAutoPrcsMngService } from "./api/ai-auto-prcs-mng-service";
export { aiAutoPrcsMngKeys, useAiAutoPrcsLatest } from "./api/queries";
export type {
AiAutoPrcsLatestResponseDto,
AiAutoPrcsMngService,
AiAutoSeComCd,
} from "./model/ai-auto-prcs-mng-interface";
export { AI_AUTO_SE } from "./model/ai-auto-prcs-mng-interface";
@@ -0,0 +1,44 @@
/** 자동화구분 공통코드 (AIAUTOSE) */
export const AI_AUTO_SE = {
FILE_VRFC: "FILE_VRFC",
DRAFT_GEN: "DRAFT_GEN",
COST_VRFC: "COST_VRFC",
} as const;
export type AiAutoSeComCd = (typeof AI_AUTO_SE)[keyof typeof AI_AUTO_SE];
/** 백엔드 AiAutoPrcsLatestResponseDto */
export interface AiAutoPrcsLatestResponseDto {
atmtnPrcsUuid?: string;
fnrsCnsltnDocNo?: string;
pwrkCnsltnDocNo?: string;
crtDmndUuid?: string;
atmtnSeComCd?: string;
atmtnSeComNm?: string;
bfrDocSttsComCd?: string;
bfrDocSttsComNm?: string;
aftrDocSttsComCd?: string;
aftrDocSttsComNm?: string;
atmtnPrcsSttsComCd?: string;
atmtnPrcsSttsComNm?: string;
dmndDt?: string;
dmndSysId?: string;
rplyDt?: string;
rplyRsltComCd?: string;
prcsErrCn?: string | null;
lastSttsInqDt?: string;
sttsInqRsltComCd?: string;
rtrsmCtpvNmtm?: number;
lastRtrsmDt?: string;
lastFrcSttsChgYn?: string;
isFailed?: boolean;
isRetryable?: boolean;
}
/** Controller public 메서드명·시그니처와 동일 */
export interface AiAutoPrcsMngService {
findLatestPerAutoSeByFnrsDocNo(
fnrsCnsltnDocNo: string,
atmtnSeComCd?: string,
): Promise<AiAutoPrcsLatestResponseDto[]>;
}
@@ -46,9 +46,40 @@ async function requestCostVerification(
return response.data;
}
async function reTransferDocument(
body: DcRagDocumentTransferRequestDto,
): Promise<DcRagCommonResponseDto> {
const response = await client.post<DcRagCommonResponseDto>(
`${BASE}/documents/re-transfer`,
body,
);
return response.data;
}
async function reGenerateDraft(
body: DcRagDraftGenerateRequestDto,
): Promise<DcRagDraftGenerateResponseDto> {
const response = await client.post<DcRagDraftGenerateResponseDto>(
`${BASE}/documents/draft/re-generate`,
body,
);
return response.data;
}
async function reVerifyCost(body: DcRagCostVerifyRequestDto): Promise<DcRagCommonResponseDto> {
const response = await client.post<DcRagCommonResponseDto>(
`${BASE}/documents/cost/re-verify`,
body,
);
return response.data;
}
export const dcRagApiToService = {
requestDocumentTransfer,
requestDraftGeneration,
getDraftGenerationStatus,
requestCostVerification,
reTransferDocument,
reGenerateDraft,
reVerifyCost,
} satisfies DcRagApiToService;
@@ -1,6 +1,9 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { ENDPOINT } from "@/shared/config";
import { useMutationWrapper } from "@/shared/lib";
import { aiAutoPrcsMngKeys } from "@/entities/ai-auto-prcs-mng";
import { fnrsCnsltnKeys } from "@/entities/fnrs-cnsltn";
import type { DcRagDraftStatusResponseDto } from "../model/dcrag-to-interface";
import type {
@@ -21,6 +24,18 @@ function isDraftGenerationSettled(data: DcRagDraftStatusResponseDto | undefined)
return data.events?.some((event) => event.eventType === "COMPLETED") ?? false;
}
function invalidateAfterAiRetry(
queryClient: ReturnType<typeof useQueryClient>,
fnrsCnsltnDocNo?: string,
) {
queryClient.invalidateQueries({ queryKey: dcRagApiToBaseKey });
queryClient.invalidateQueries({ queryKey: aiAutoPrcsMngKeys.all });
if (fnrsCnsltnDocNo) {
queryClient.invalidateQueries({ queryKey: fnrsCnsltnKeys.detail(fnrsCnsltnDocNo) });
queryClient.invalidateQueries({ queryKey: fnrsCnsltnKeys.all });
}
}
export function useDraftGenerationStatus(crtDmndUuid: string | null | undefined) {
return useQuery({
queryKey: [...dcRagApiToBaseKey, "getDraftGenerationStatus", crtDmndUuid],
@@ -68,3 +83,39 @@ export function useRequestCostVerification() {
},
});
}
export function useReTransferDocument() {
const queryClient = useQueryClient();
return useMutationWrapper({
mutationFn: (body: DcRagDocumentTransferRequestDto) =>
dcRagApiToService.reTransferDocument(body),
onSuccess: (_data, body) => {
invalidateAfterAiRetry(queryClient, body.fnrsCnsltnDocNo);
},
});
}
export function useReGenerateDraft() {
const queryClient = useQueryClient();
return useMutationWrapper({
mutationFn: (body: DcRagDraftGenerateRequestDto) => dcRagApiToService.reGenerateDraft(body),
onSuccess: (_data, body) => {
invalidateAfterAiRetry(queryClient, body.fnrsCnsltnDocNo);
if (body.crtDmndUuid) {
queryClient.invalidateQueries({
queryKey: [...dcRagApiToBaseKey, "getDraftGenerationStatus", body.crtDmndUuid],
});
}
},
});
}
export function useReVerifyCost() {
const queryClient = useQueryClient();
return useMutationWrapper({
mutationFn: (body: DcRagCostVerifyRequestDto) => dcRagApiToService.reVerifyCost(body),
onSuccess: (_data, body) => {
invalidateAfterAiRetry(queryClient, body.fnrsCnsltnDocNo);
},
});
}
+3
View File
@@ -2,9 +2,12 @@ export { dcRagApiToService } from "./api/dcrag-to-service";
export { dcRagApiToBaseKey } from "./api/queries";
export {
useDraftGenerationStatus,
useReGenerateDraft,
useRequestCostVerification,
useRequestDocumentTransfer,
useRequestDraftGeneration,
useReTransferDocument,
useReVerifyCost,
} from "./api/queries";
export type {
DcRagApiToService,
@@ -49,4 +49,7 @@ export interface DcRagApiToService {
): Promise<DcRagDraftGenerateResponseDto>;
getDraftGenerationStatus(crtDmndUuid: string): Promise<DcRagDraftStatusResponseDto>;
requestCostVerification(body: DcRagCostVerifyRequestDto): Promise<DcRagCommonResponseDto>;
reTransferDocument(body: DcRagDocumentTransferRequestDto): Promise<DcRagCommonResponseDto>;
reGenerateDraft(body: DcRagDraftGenerateRequestDto): Promise<DcRagDraftGenerateResponseDto>;
reVerifyCost(body: DcRagCostVerifyRequestDto): Promise<DcRagCommonResponseDto>;
}
@@ -9,6 +9,7 @@ export const FNRS_CNSLTN_VIEW_BUTTON_ACTION = {
rvwOpnnRply: "rvwOpnnRply",
rqstTechRvw: "rqstTechRvw",
fileSplmnt: "fileSplmnt",
fileVrfc: "fileVrfc",
dsgntRvwr: "dsgntRvwr",
pwrkCnsltnDocCrt: "pwrkCnsltnDocCrt",
pwrkCnsltnDocMng: "pwrkCnsltnDocMng",
@@ -20,6 +21,7 @@ export const FNRS_CNSLTN_VIEW_BUTTON_ACTION = {
atrzRply: "atrzRply",
actnCmptn: "actnCmptn",
rqstActnRvw: "rqstActnRvw",
costVrfc: "costVrfc",
} as const;
export type FnrsCnsltnViewButtonAction =
@@ -80,7 +82,11 @@ const ROLE_USER01_ATRZ_STATUS_ACTIONS: Record<
Record<string, FnrsCnsltnViewButtonAction[]>
> = {
ER: {
ATRZ01: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.fileSplmnt, FNRS_CNSLTN_VIEW_BUTTON_ACTION.dsgntRvwr],
ATRZ01: [
FNRS_CNSLTN_VIEW_BUTTON_ACTION.fileSplmnt,
FNRS_CNSLTN_VIEW_BUTTON_ACTION.fileVrfc,
FNRS_CNSLTN_VIEW_BUTTON_ACTION.dsgntRvwr,
],
},
SL: {
ATRZ01: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
@@ -136,7 +142,10 @@ const ROLE_USER01_ATRZ_STATUS_ACTIONS: Record<
FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng,
FNRS_CNSLTN_VIEW_BUTTON_ACTION.dsgntRvwr,
],
ATRZ02: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
ATRZ02: [
FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng,
FNRS_CNSLTN_VIEW_BUTTON_ACTION.costVrfc,
],
ATRZ03: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
ATRZ99: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
},
@@ -183,6 +192,9 @@ function resolveButtonConfigs(actions: FnrsCnsltnViewButtonAction[]): FnrsCnsltn
interface GetButtonConfigsOptions {
hasPendingApprovalRequest?: boolean;
hasCompletedDraft?: boolean;
canRetryFileVrfc?: boolean;
canRetryDraftGen?: boolean;
canRetryCostVrfc?: boolean;
}
const PENDING_APPROVAL_ACTIONS = new Set<FnrsCnsltnViewButtonAction>([
@@ -220,6 +232,16 @@ function resolveRoleUser01AtrzButtonActions(
const needsPendingApproval = PENDING_APPROVAL_ACTIONS.has(action);
if (needsPendingApproval && options?.hasPendingApprovalRequest === false) return false;
if (action === FNRS_CNSLTN_VIEW_BUTTON_ACTION.fileVrfc) {
return options?.canRetryFileVrfc === true;
}
if (action === FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocCrt) {
return options?.canRetryDraftGen === true;
}
if (action === FNRS_CNSLTN_VIEW_BUTTON_ACTION.costVrfc) {
return options?.canRetryCostVrfc === true;
}
if (options?.hasCompletedDraft != null) {
if (prgrsSttsComCd === "SL" || prgrsSttsComCd === "TE" || prgrsSttsComCd === "RK") {
if (action === FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng) {
@@ -230,9 +252,6 @@ function resolveRoleUser01AtrzButtonActions(
if (action === FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwRsltInq) {
return options.hasCompletedDraft;
}
if (action === FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocCrt) {
return !options.hasCompletedDraft;
}
}
}
@@ -9,6 +9,12 @@ import { AxiosError } from "axios";
import { ENDPOINT } from "@/shared/config";
import { useAlertStore, useUserStore } from "@/shared/lib";
import {
AI_AUTO_SE,
type AiAutoPrcsLatestResponseDto,
useAiAutoPrcsLatest,
} from "@/entities/ai-auto-prcs-mng";
import { useReGenerateDraft, useReTransferDocument, useReVerifyCost } from "@/entities/dcrag-to";
import {
buildElaprPrgrsSttsListFromAplnRows,
ElaprApprovalDialog,
@@ -64,6 +70,15 @@ import { FileVrfcSplmntDialog } from "./file-vrfc-splmnt-dialog";
import { PwrkCnsltnDocMngDialog } from "./pwrk-cnsltn-doc-mng-dialog";
import { PwrkCnsltnRvwRsltInqDialog } from "./pwrk-cnsltn-rvw-rslt-inq-dialog";
const AI_RETRY_PRGRS_STTS = new Set(["ER", "TE", "EV"]);
function findLatestByAutoSe(
list: AiAutoPrcsLatestResponseDto[] | undefined,
atmtnSeComCd: string,
): AiAutoPrcsLatestResponseDto | undefined {
return list?.find((item) => item.atmtnSeComCd === atmtnSeComCd);
}
interface FloatingActionButtonsProps {
data: FnrsCnsltnMngDetResponseDto;
docSeComCd: string;
@@ -118,7 +133,9 @@ function FloatingActionButtons({
const needsPwrkDraftCheck =
dtlInstCd === "ROLE_USER01" && ["SL", "TE", "RK"].includes(prgrsSttsComCd);
const needsPwrkForRb = dtlInstCd === "ROLE_USER05" && prgrsSttsComCd === "RB";
const needsPwrkLookup = needsPwrkDraftCheck || needsPwrkForRb;
const needsPwrkForAiRetry = dtlInstCd === "ROLE_USER01" && ["TE", "EV"].includes(prgrsSttsComCd);
const needsPwrkLookup = needsPwrkDraftCheck || needsPwrkForRb || needsPwrkForAiRetry;
const needsAiAutoLatest = dtlInstCd === "ROLE_USER01" && AI_RETRY_PRGRS_STTS.has(prgrsSttsComCd);
const { data: elaprDocPrgrsList = [], isLoading: isElaprDocPrgrsLoading } =
useElaprDocPrgrsByDocNo(needsElaprPrgrsCheck ? docNo : null);
@@ -128,8 +145,31 @@ function FloatingActionButtons({
needsPwrkLookup,
);
const { data: aiAutoLatestList, isLoading: isAiAutoLatestLoading } = useAiAutoPrcsLatest(docNo, {
enabled: needsAiAutoLatest,
});
const fileVrfcLatest = findLatestByAutoSe(aiAutoLatestList, AI_AUTO_SE.FILE_VRFC);
const draftGenLatest = findLatestByAutoSe(aiAutoLatestList, AI_AUTO_SE.DRAFT_GEN);
const costVrfcLatest = findLatestByAutoSe(aiAutoLatestList, AI_AUTO_SE.COST_VRFC);
const canRetryFileVrfc = fileVrfcLatest?.isRetryable === true;
const canRetryDraftGen = draftGenLatest?.isRetryable === true;
const canRetryCostVrfc = costVrfcLatest?.isRetryable === true;
const reTransferDocument = useReTransferDocument();
const reGenerateDraft = useReGenerateDraft();
const reVerifyCost = useReVerifyCost();
const isBusy =
isProcessing ||
reTransferDocument.isPending ||
reGenerateDraft.isPending ||
reVerifyCost.isPending;
const hasCompletedDraft = Boolean(findCompletedPwrkDraft(pwrkCnsltnData));
const pwrkCnsltnDocNo = pwrkCnsltnData?.pwrkCnsltnDocNo;
const pwrkCnsltnDocNo =
pwrkCnsltnData?.pwrkCnsltnDocNo ??
draftGenLatest?.pwrkCnsltnDocNo ??
costVrfcLatest?.pwrkCnsltnDocNo;
const elaprPrgrsForPending =
prgrsSttsComCd === "RK"
@@ -146,18 +186,27 @@ function FloatingActionButtons({
if (needsAtrzResolve && isRvwLoginUserLoading) return [];
if (needsElaprPrgrsCheck && isElaprDocPrgrsLoading) return [];
if (needsPwrkDraftCheck && isPwrkCnsltnLoading) return [];
if (needsAiAutoLatest && isAiAutoLatestLoading) return [];
return getButtonConfigs(dtlInstCd, prgrsSttsComCd, atrzSeComCdList, {
hasPendingApprovalRequest: needsElaprPrgrsCheck ? hasPendingApprovalRequest : undefined,
hasCompletedDraft: needsPwrkDraftCheck ? hasCompletedDraft : undefined,
canRetryFileVrfc: needsAiAutoLatest ? canRetryFileVrfc : undefined,
canRetryDraftGen: needsAiAutoLatest ? canRetryDraftGen : undefined,
canRetryCostVrfc: needsAiAutoLatest ? canRetryCostVrfc : undefined,
});
}, [
atrzSeComCdList,
canRetryCostVrfc,
canRetryDraftGen,
canRetryFileVrfc,
dtlInstCd,
hasCompletedDraft,
hasPendingApprovalRequest,
isAiAutoLatestLoading,
isElaprDocPrgrsLoading,
isPwrkCnsltnLoading,
isRvwLoginUserLoading,
needsAiAutoLatest,
needsAtrzResolve,
needsElaprPrgrsCheck,
needsPwrkDraftCheck,
@@ -544,17 +593,60 @@ function FloatingActionButtons({
});
}
function handleFileVrfcClick() {
reTransferDocument.mutate(
{ fnrsCnsltnDocNo: docNo },
{ onSuccess: () => alert("파일 검증을 요청했습니다.") },
);
}
function handlePwrkCnsltnDocCrtClick() {
if (!pwrkCnsltnDocNo) {
alert("실무협의 문서번호를 찾을 수 없습니다.");
return;
}
reGenerateDraft.mutate(
{
fnrsCnsltnDocNo: docNo,
pwrkCnsltnDocNo,
crtDmndUuid: draftGenLatest?.crtDmndUuid,
},
{ onSuccess: () => alert("초안 생성을 요청했습니다.") },
);
}
function handleCostVrfcClick() {
if (!pwrkCnsltnDocNo) {
alert("실무협의 문서번호를 찾을 수 없습니다.");
return;
}
reVerifyCost.mutate(
{
fnrsCnsltnDocNo: docNo,
pwrkCnsltnDocNo,
},
{ onSuccess: () => alert("금액 검증을 요청했습니다.") },
);
}
return (
<>
<div className="sticky bottom-0 z-40 !-mb-2 border-t bg-white pb-8 pt-6 shadow-[0_-4px_12px_rgba(0,0,0,0.06)]">
<div className="mx-4 flex flex-wrap justify-center gap-3 sm:gap-4">
<Button color="white" type="button" onClick={handleGoToList} disabled={isProcessing}>
<Button color="white" type="button" onClick={handleGoToList} disabled={isBusy}>
목록
</Button>
{!isAiPending && (
<>
{shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocCrt) && (
<Button color="orange" onClick={() => {}} disabled={isProcessing}>
<Button
color="orange"
onClick={handlePwrkCnsltnDocCrtClick}
disabled={isBusy}
title={draftGenLatest?.prcsErrCn ?? undefined}
>
실무협의서 초안 생성
</Button>
)}
@@ -562,85 +654,103 @@ function FloatingActionButtons({
<Button
color="orange"
onClick={() => setActiveDialog("pwrkCnsltnDocMng")}
disabled={isProcessing}
disabled={isBusy}
>
실무협의서 관리
</Button>
)}
{canEdit && (
<Button color="gray" onClick={handleEdit} disabled={isProcessing}>
<Button color="gray" onClick={handleEdit} disabled={isBusy}>
수정
</Button>
)}
{shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.strg) && (
<Button onClick={handleStrgClick} disabled={isProcessing}>
<Button onClick={handleStrgClick} disabled={isBusy}>
저장
</Button>
)}
{shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.aply) && (
<Button color="green" onClick={handleAplyClick} disabled={isProcessing}>
<Button color="green" onClick={handleAplyClick} disabled={isBusy}>
신청 완료
</Button>
)}
{shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.del) && (
<Button color="red" onClick={handleDelClick} disabled={isProcessing}>
<Button color="red" onClick={handleDelClick} disabled={isBusy}>
삭제
</Button>
)}
{shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.envoSbmsn) && (
<Button onClick={handleEnvoSbmsnClick} disabled={isProcessing}>
<Button onClick={handleEnvoSbmsnClick} disabled={isBusy}>
환경청 제출
</Button>
)}
{shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rjct) && (
<Button color="red" onClick={handleRjctClick} disabled={isProcessing}>
<Button color="red" onClick={handleRjctClick} disabled={isBusy}>
반려
</Button>
)}
{shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.sncnAprv) && (
<Button color="green" onClick={handleSncnAprvClick} disabled={isProcessing}>
<Button color="green" onClick={handleSncnAprvClick} disabled={isBusy}>
결과 회신
</Button>
)}
{shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwOpnnRply) && (
<Button onClick={handleRvwOpnnRplyClick} disabled={isProcessing}>
<Button onClick={handleRvwOpnnRplyClick} disabled={isBusy}>
검토 의견 회신
</Button>
)}
{shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwRply) && (
<Button color="green" onClick={handleRvwRplyClick} disabled={isProcessing}>
<Button color="green" onClick={handleRvwRplyClick} disabled={isBusy}>
검토 결과 회신
</Button>
)}
{shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rqstTechRvw) && (
<Button onClick={handleRqstTechRvwClick} disabled={isProcessing}>
<Button onClick={handleRqstTechRvwClick} disabled={isBusy}>
기술 검토 의뢰
</Button>
)}
{shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rqstActnRvw) && (
<Button onClick={handleRqstActnRvwClick} disabled={isProcessing}>
<Button onClick={handleRqstActnRvwClick} disabled={isBusy}>
조치 결과 검토 의뢰
</Button>
)}
{shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.fileSplmnt) && (
<Button color="gray" onClick={handleFileSplmntClick} disabled={isProcessing}>
<Button color="gray" onClick={handleFileSplmntClick} disabled={isBusy}>
파일 보완 요청
</Button>
)}
{shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.fileVrfc) && (
<Button
onClick={handleFileVrfcClick}
disabled={isBusy}
title={fileVrfcLatest?.prcsErrCn ?? undefined}
>
파일 검증
</Button>
)}
{shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.dsgntRvwr) &&
!isRagIndexingInProgress(prgrsSttsComCd, data.ragIndexingInfo) && (
<Button
onClick={() =>
setActiveDialog(prgrsSttsComCd === "EV" ? "elaprDocPrgrs" : "elaprTmplt")
}
disabled={isProcessing}
disabled={isBusy}
>
검토자 지정
</Button>
)}
{shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.costVrfc) && (
<Button
onClick={handleCostVrfcClick}
disabled={isBusy}
title={costVrfcLatest?.prcsErrCn ?? undefined}
>
금액 검증
</Button>
)}
{shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.actnCmptn) && (
<Button color="green" onClick={handleActnCmptnClick} disabled={isProcessing}>
<Button color="green" onClick={handleActnCmptnClick} disabled={isBusy}>
조치 완료
</Button>
)}
@@ -648,18 +758,18 @@ function FloatingActionButtons({
<Button
color="sky"
onClick={() => setActiveDialog("rvwRsltInq")}
disabled={isProcessing}
disabled={isBusy}
>
검토 결과 조회
</Button>
)}
{shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwStrg) && (
<Button onClick={handleRvwStrgClick} disabled={isProcessing}>
<Button onClick={handleRvwStrgClick} disabled={isBusy}>
저장
</Button>
)}
{shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwCmptn) && (
<Button color="green" onClick={handleRvwCmptnClick} disabled={isProcessing}>
<Button color="green" onClick={handleRvwCmptnClick} disabled={isBusy}>
검토 완료
</Button>
)}
@@ -667,18 +777,18 @@ function FloatingActionButtons({
<Button
color="gray"
onClick={() => setActiveDialog("dmndSplmnt")}
disabled={isProcessing}
disabled={isBusy}
>
보완 요청
</Button>
)}
{shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.atrzAprv) && (
<Button onClick={() => setActiveDialog("elaprApproval")} disabled={isProcessing}>
<Button onClick={() => setActiveDialog("elaprApproval")} disabled={isBusy}>
결재(승인)
</Button>
)}
{shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.atrzRply) && (
<Button onClick={() => setActiveDialog("elaprApproval")} disabled={isProcessing}>
<Button onClick={() => setActiveDialog("elaprApproval")} disabled={isBusy}>
결재(회신)
</Button>
)}
@@ -707,14 +817,14 @@ function FloatingActionButtons({
splmntArtclUpCd="SPLMNTARTCL"
open={activeDialog === "dmndSplmnt"}
onOpenChange={() => setActiveDialog(null)}
isSubmitting={isProcessing}
isSubmitting={isBusy}
onConfirm={handleDmndSplmntConfirm}
/>
<FileVrfcSplmntDialog
open={activeDialog === "fileSplmnt"}
fnrsCnsltnDocNo={docNo}
isSubmitting={isProcessing}
isSubmitting={isBusy}
onClose={() => setActiveDialog(null)}
onConfirm={handleFileSplmntConfirm}
/>
@@ -748,7 +858,7 @@ function FloatingActionButtons({
<PwrkCnsltnRvwRsltInqDialog
open={activeDialog === "rvwRsltInq"}
fnrsCnsltnDocNo={docNo}
isSubmitting={isProcessing}
isSubmitting={isBusy}
onClose={() => setActiveDialog(null)}
onConfirm={handleRvwRsltSplmntConfirm}
/>
@@ -883,6 +993,7 @@ const buttonActionHandlers: Record<FnrsCnsltnViewButtonAction, ActionHandler> =
rvwOpnnRply: handleTechReview,
rqstTechRvw: handleRequestExamine,
fileSplmnt: handleDmndSplmnt,
fileVrfc: () => Promise.resolve(),
dsgntRvwr: handleDsgntRvwr,
pwrkCnsltnDocCrt: () => Promise.resolve(),
pwrkCnsltnDocMng: () => Promise.resolve(),
@@ -894,6 +1005,7 @@ const buttonActionHandlers: Record<FnrsCnsltnViewButtonAction, ActionHandler> =
atrzRply: () => Promise.resolve(),
actnCmptn: handleActnCmptn,
rqstActnRvw: handleRequestActnReview,
costVrfc: () => Promise.resolve(),
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
+1
View File
@@ -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",