From 94d79908fb32e1d4eb0e9a3e5860249340f65193 Mon Sep 17 00:00:00 2001
From: jangwoong
Date: Wed, 28 Oct 2026 20:04:34 +0900
Subject: [PATCH] =?UTF-8?q?[as=20fr]=20=EB=B3=91=ED=95=A9=EC=9E=90=20?=
=?UTF-8?q?=EC=A1=B0=EC=B9=98=EC=9A=94=EC=B2=AD=20=EC=9E=91=EC=84=B1=20?=
=?UTF-8?q?=EB=B2=84=ED=8A=BC=EC=97=90=20=EC=B6=94=EA=B0=80=EB=B0=8F=20TB?=
=?UTF-8?q?=20=EB=8B=A8=EA=B3=84=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../fnrs-cnsltn/api/fnrs-cnsltn-service.ts | 10 ++
.../model/fnrs-cnsltn-interface.ts | 2 +
.../pages/fnrs-cnsltn/lib/button-config.ts | 36 +++++-
.../src/pages/fnrs-cnsltn/model/view-types.ts | 1 +
.../ui/components/floating-action-buttons.tsx | 103 ++++++++++++++++--
.../components/pwrk-cnsltn-doc-mng-dialog.tsx | 13 ++-
6 files changed, 149 insertions(+), 16 deletions(-)
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 a74838d49..585008dc4 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
@@ -68,6 +68,14 @@ async function requestActnReview(docNo: string, body: EnvoActnReviewReqDto): Pro
return response.data;
}
+async function tbActnRqst(docNo: string): Promise {
+ await client.put(`${BASE}/${docNo}/tb-actn-rqst`);
+}
+
+async function tbSubmitActnResult(docNo: string, body: { isSubmit: boolean }): Promise {
+ await client.post(`${BASE}/${docNo}/tb-submit-actn-result`, body);
+}
+
async function submitSupplement(id: string, body: FnrsCnsltnApplySaveRequestDto): Promise {
const response = await client.post(`${BASE}/${id}/submitsupplement`, body);
return response.data;
@@ -111,6 +119,8 @@ export const fnrsCnsltnMngService = {
techReview,
requestExamine,
requestActnReview,
+ tbActnRqst,
+ tbSubmitActnResult,
submitSupplement,
submitReqSupplement,
remove,
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 adfd40338..a5e289137 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
@@ -140,6 +140,8 @@ export interface FnrsCnsltnMngService {
techReview(id: string, body: FnrsCnsltnApplySaveRequestDto): Promise;
requestExamine(docNo: string, body: FnrsExamineRequestDto): Promise;
requestActnReview(docNo: string, body: EnvoActnReviewReqDto): Promise;
+ tbActnRqst(docNo: string): Promise;
+ tbSubmitActnResult(docNo: string, body: { isSubmit: boolean }): Promise;
submitSupplement(id: string, body: FnrsCnsltnApplySaveRequestDto): Promise;
submitReqSupplement(id: string, body: FnrsCnsltnApplySaveRequestDto): Promise;
remove(fnrsCnsltnDocNo: string): Promise;
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 222adb75c..244dcdc9a 100644
--- a/apps/as/src/pages/fnrs-cnsltn/lib/button-config.ts
+++ b/apps/as/src/pages/fnrs-cnsltn/lib/button-config.ts
@@ -22,6 +22,8 @@ export const FNRS_CNSLTN_VIEW_BUTTON_ACTION = {
actnCmptn: "actnCmptn",
rqstActnRvw: "rqstActnRvw",
costVrfc: "costVrfc",
+ tbActnRqst: "tbActnRqst",
+ tbSubmitActnRslt: "tbSubmitActnRslt",
} as const;
export type FnrsCnsltnViewButtonAction =
@@ -40,6 +42,10 @@ const ROLE_STATUS_BUTTON_ACTIONS: Record([
FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwCmptn,
FNRS_CNSLTN_VIEW_BUTTON_ACTION.atrzAprv,
FNRS_CNSLTN_VIEW_BUTTON_ACTION.atrzRply,
+ FNRS_CNSLTN_VIEW_BUTTON_ACTION.tbActnRqst,
]);
function resolveRoleUser01AtrzButtonActions(
@@ -349,7 +373,10 @@ function resolveRoleUser01AtrzButtonActions(
): FnrsCnsltnViewButtonAction[] {
let effectiveStatus = prgrsSttsComCd;
- if (options?.isForkJoin && options?.branchSttsCd) {
+ // TB는 문서 단위 상태이고 결재 브랜치는 IN_PROGRESS로 남는다. TE 맵으로 되돌리지 않는다.
+ if (prgrsSttsComCd === "TB") {
+ effectiveStatus = "TB";
+ } else if (options?.isForkJoin && options?.branchSttsCd) {
switch (options.branchSttsCd) {
case "SUPPLEMENT":
// 본인 브랜치가 보완요청 중이면 'SL' 맵핑 적용 (검토/승인 버튼 숨김, 실무협의서관리만 노출)
@@ -415,7 +442,12 @@ function resolveRoleUser01AtrzButtonActions(
}
if (options?.hasCompletedDraft != null) {
- if (effectiveStatus === "SL" || effectiveStatus === "TE" || effectiveStatus === "RK") {
+ if (
+ effectiveStatus === "SL" ||
+ effectiveStatus === "TE" ||
+ effectiveStatus === "TB" ||
+ effectiveStatus === "RK"
+ ) {
if (action === FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng) {
return options.hasCompletedDraft;
}
diff --git a/apps/as/src/pages/fnrs-cnsltn/model/view-types.ts b/apps/as/src/pages/fnrs-cnsltn/model/view-types.ts
index 60e4e73f3..f5ef40035 100644
--- a/apps/as/src/pages/fnrs-cnsltn/model/view-types.ts
+++ b/apps/as/src/pages/fnrs-cnsltn/model/view-types.ts
@@ -82,6 +82,7 @@ export const PBADMS_PROGRESS_ORDER = [
// KECO
"ER",
"TE",
+ "TB",
"EV",
"RK",
] as const;
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 383f6caca..a3d52c446 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
@@ -146,10 +146,11 @@ function FloatingActionButtons({
const needsAtrzResolve = needsRoleUser01AtrzResolve(dtlInstCd, prgrsSttsComCd);
const needsElaprPrgrsCheck =
needsAtrzResolve &&
- (["TE", "RK"].includes(prgrsSttsComCd) || (isForkJoin && prgrsSttsComCd === "SL"));
+ (["TE", "TB", "RK"].includes(prgrsSttsComCd) || (isForkJoin && prgrsSttsComCd === "SL"));
const needsPwrkDraftCheck =
- dtlInstCd === "ROLE_USER01" && ["SL", "TE", "RK"].includes(prgrsSttsComCd);
- const needsPwrkForRb = dtlInstCd === "ROLE_USER05" && prgrsSttsComCd === "RB";
+ dtlInstCd === "ROLE_USER01" && ["SL", "TE", "TB", "RK"].includes(prgrsSttsComCd);
+ const needsPwrkForRb =
+ dtlInstCd === "ROLE_USER05" && (prgrsSttsComCd === "RB" || prgrsSttsComCd === "TB");
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);
@@ -384,14 +385,22 @@ function FloatingActionButtons({
await handler({
request,
data,
- onSuccess: () => {
+ onSuccess: async () => {
if (successMessage) alert(successMessage);
- queryClient.invalidateQueries({
- queryKey: fnrsCnsltnKeys.detail(fnrsCnsltnDocNo),
- });
- queryClient.invalidateQueries({
- queryKey: [ENDPOINT.AS_ELAPR_SERVICE.ELAPR_BRANCH],
- });
+ await Promise.all([
+ queryClient.invalidateQueries({
+ queryKey: fnrsCnsltnKeys.detail(fnrsCnsltnDocNo),
+ refetchType: "all",
+ }),
+ queryClient.invalidateQueries({
+ queryKey: [ENDPOINT.AS_ELAPR_SERVICE.ELAPR_BRANCH],
+ refetchType: "all",
+ }),
+ queryClient.invalidateQueries({
+ queryKey: [ENDPOINT.AS_ELAPR_SERVICE.ELAPR_DMND],
+ refetchType: "all",
+ }),
+ ]);
},
onError: (error) => {
let errorMessage = "";
@@ -771,6 +780,37 @@ function FloatingActionButtons({
});
}
+ async function handleTbActnRqstClick() {
+ if (
+ !(await confirm(
+ "지자체에 조치요청하시겠습니까?\n조치요청 후 7일 내 제출하지 않으면 자동으로 결재가 다음 단계로 진행됩니다.",
+ ))
+ ) {
+ return;
+ }
+ await executeAction({
+ action: FNRS_CNSLTN_VIEW_BUTTON_ACTION.tbActnRqst,
+ successMessage: "조치요청이 완료되었습니다.",
+ });
+ }
+
+ async function handleTbSubmitActnRsltClick() {
+ if (!pwrkCnsltnDocNo) {
+ alert("실무협의 문서번호를 찾을 수 없습니다.");
+ return;
+ }
+ if (!(await confirm("조치결과를 제출하시겠습니까?"))) return;
+
+ await executeAction({
+ action: FNRS_CNSLTN_VIEW_BUTTON_ACTION.tbSubmitActnRslt,
+ request: {
+ pwrkCnsltnDocNo,
+ body: { isSubmit: true } satisfies PwrkActnResultSubmitDto,
+ },
+ successMessage: "조치결과가 제출되었습니다.",
+ });
+ }
+
function handleFileVrfcClick() {
reTransferDocument.mutate(
{ fnrsCnsltnDocNo: docNo },
@@ -940,6 +980,17 @@ function FloatingActionButtons({
조치 완료
)}
+ {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.tbActnRqst) &&
+ prgrsSttsComCd !== "TB" && (
+
+ )}
+ {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.tbSubmitActnRslt) && (
+
+ )}
{shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwRsltInq) &&
!isSecondApproval &&
!(
@@ -970,6 +1021,7 @@ function FloatingActionButtons({
)}
{shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.atrzAprv) &&
+ prgrsSttsComCd !== "TB" &&
(!isForkJoin ||
(userPendingBranchSeCd === "TOTAL_AGG" && userPendingAtrzSeComCd === "ATRZ04")) && (
) : null}
- {completedDraft && documentBlob ? (
+ {hideHangulForLocalUser ? (
+
+ 기술검토(TE) 이후 보완요청(SL) 상태에서는 지자체 사용자에게 웹기안기가 표시되지 않습니다.
+
+ ) : null}
+ {completedDraft && documentBlob && !hideHangulForLocalUser ? (