diff --git a/apps/as/src/entities/elapr/ui/elapr-forkjoin-picker-grid.tsx b/apps/as/src/entities/elapr/ui/elapr-forkjoin-picker-grid.tsx
index 7aa92cde0..6f7428b4c 100644
--- a/apps/as/src/entities/elapr/ui/elapr-forkjoin-picker-grid.tsx
+++ b/apps/as/src/entities/elapr/ui/elapr-forkjoin-picker-grid.tsx
@@ -58,7 +58,7 @@ const TRACK_CONFIGS: TrackConfig[] = [
key: "TOTAL_AGG",
label: "정책부 종합병합",
defaultDeptNm: "정책총괄부",
- guideText: "ℹ️ 두 부서(관로+시설) Join 완료 후 정책취합 및 환경청 최종회신 단계로 진행됩니다.",
+ guideText: "ℹ️ 두 부서(관로+시설) Join 완료 후 정책취합 및 환경청 회신 단계로 진행됩니다.",
minCount: 2,
maxCount: 5,
},
@@ -107,7 +107,7 @@ export function ElaprForkJoinPickerGrid({
],
TOTAL_AGG: [
createDefaultRow("TOTAL_AGG", "정책총괄부", 1, "ATRZ04"), // 병합 (10-12 신설)
- createDefaultRow("TOTAL_AGG", "정책총괄부", 2, "ATRZ99"), // 최종승인/전결 (환경청 최종회신)
+ createDefaultRow("TOTAL_AGG", "정책총괄부", 2, "ATRZ99"), // 최종승인/전결 (환경청 회신)
],
}));
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 243f72b27..d72503d1c 100644
--- a/apps/as/src/pages/fnrs-cnsltn/lib/button-config.ts
+++ b/apps/as/src/pages/fnrs-cnsltn/lib/button-config.ts
@@ -188,16 +188,149 @@ const ROLE_USER01_ATRZ_STATUS_ACTIONS: Record<
},
};
+/**
+ * Fork-Join (병렬 결재 6인 체제: 관로2 + 시설2 + 정책병합2) 전용 상태별 버튼 액션 매핑
+ * - Stage 2: 관로/시설 실무검토자(ATRZ02), 부서승인자(ATRZ03)
+ * - Stage 3: 정책총괄 종합병합자(ATRZ04), 최종회신자(ATRZ99)
+ * - 일반 순차 결재 라인과 분리하여 독립적으로 관리
+ */
+const ROLE_USER01_FORK_JOIN_ATRZ_STATUS_ACTIONS: Record<
+ string,
+ Record
+> = {
+ ER: {
+ 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],
+ ATRZ02: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ03: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ04: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ99: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ },
+ TE: {
+ ATRZ01: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ02: [
+ FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocCrt,
+ FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng,
+ FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwRsltInq,
+ FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwStrg,
+ FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwCmptn,
+ FNRS_CNSLTN_VIEW_BUTTON_ACTION.dmndSplmnt,
+ ],
+ ATRZ03: [
+ FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng,
+ FNRS_CNSLTN_VIEW_BUTTON_ACTION.atrzAprv,
+ FNRS_CNSLTN_VIEW_BUTTON_ACTION.atrzRply,
+ ],
+ ATRZ04: [
+ FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng,
+ FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwRsltInq,
+ FNRS_CNSLTN_VIEW_BUTTON_ACTION.atrzAprv,
+ ],
+ ATRZ99: [
+ FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng,
+ FNRS_CNSLTN_VIEW_BUTTON_ACTION.atrzRply,
+ ],
+ },
+ TP: {
+ ATRZ01: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ02: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ03: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ04: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ99: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ },
+ RB: {
+ ATRZ01: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ02: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ03: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ04: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ99: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ },
+ RA: {
+ ATRZ01: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ02: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ03: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ04: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ99: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ },
+ AV: {
+ ATRZ01: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ02: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ03: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ04: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ99: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ },
+ EV: {
+ ATRZ01: [
+ FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng,
+ FNRS_CNSLTN_VIEW_BUTTON_ACTION.dsgntRvwr,
+ FNRS_CNSLTN_VIEW_BUTTON_ACTION.costVrfc,
+ ],
+ ATRZ02: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ03: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ04: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ99: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ },
+ RK: {
+ ATRZ01: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ02: [
+ FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng,
+ FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwCmptn,
+ FNRS_CNSLTN_VIEW_BUTTON_ACTION.dmndSplmnt,
+ ],
+ ATRZ03: [
+ FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng,
+ FNRS_CNSLTN_VIEW_BUTTON_ACTION.atrzAprv,
+ FNRS_CNSLTN_VIEW_BUTTON_ACTION.atrzRply,
+ ],
+ ATRZ04: [
+ FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng,
+ FNRS_CNSLTN_VIEW_BUTTON_ACTION.atrzAprv,
+ ],
+ ATRZ99: [
+ FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng,
+ FNRS_CNSLTN_VIEW_BUTTON_ACTION.atrzRply,
+ ],
+ },
+ RR: {
+ ATRZ01: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ02: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ03: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ04: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ99: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ },
+ EP: {
+ ATRZ01: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ02: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ03: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ04: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ99: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ },
+ TA: {
+ ATRZ01: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ02: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ03: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ04: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ ATRZ99: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
+ },
+};
+
function resolveButtonConfigs(actions: FnrsCnsltnViewButtonAction[]): FnrsCnsltnViewButtonAction[] {
return actions.map((action) => FNRS_CNSLTN_VIEW_BUTTON_ACTION[action]);
}
-interface GetButtonConfigsOptions {
+export interface GetButtonConfigsOptions {
hasPendingApprovalRequest?: boolean;
hasCompletedDraft?: boolean;
canRetryFileVrfc?: boolean;
canRetryDraftGen?: boolean;
canRetryCostVrfc?: boolean;
+ isForkJoin?: boolean;
}
const PENDING_APPROVAL_ACTIONS = new Set([
@@ -214,7 +347,9 @@ function resolveRoleUser01AtrzButtonActions(
atrzSeComCdList: string[],
options?: GetButtonConfigsOptions,
): FnrsCnsltnViewButtonAction[] {
- const atrzStatusMap = ROLE_USER01_ATRZ_STATUS_ACTIONS[prgrsSttsComCd];
+ const atrzStatusMap = options?.isForkJoin
+ ? ROLE_USER01_FORK_JOIN_ATRZ_STATUS_ACTIONS[prgrsSttsComCd]
+ : ROLE_USER01_ATRZ_STATUS_ACTIONS[prgrsSttsComCd];
if (!atrzStatusMap || atrzSeComCdList.length === 0) return [];
const seen = new Set();
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 28f23264d..90b27befa 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
@@ -194,6 +194,15 @@ function FloatingActionButtons({
const normalizedTaskSeComCd = normalizeTaskSeComCdForElapr(data.detDto?.taskSeComCd);
const isForkJoin = isForkJoinTask(data.detDto?.taskSeComCd);
+ const effectiveAtrzSeComCdList = useMemo(() => {
+ if (isForkJoin && userPendingAtrzSeComCd) {
+ if (!atrzSeComCdList.includes(userPendingAtrzSeComCd)) {
+ return [...atrzSeComCdList, userPendingAtrzSeComCd];
+ }
+ }
+ return atrzSeComCdList;
+ }, [atrzSeComCdList, isForkJoin, userPendingAtrzSeComCd]);
+
const viewOnlyPwrkCnsltnDoc =
prgrsSttsComCd === "SL" ||
(prgrsSttsComCd === "RB" && dtlInstCd !== "ROLE_USER05") ||
@@ -204,23 +213,25 @@ function FloatingActionButtons({
if (needsElaprPrgrsCheck && isElaprDocPrgrsLoading) return [];
if (needsPwrkDraftCheck && isPwrkCnsltnLoading) return [];
if (needsAiAutoLatest && isAiAutoLatestLoading) return [];
- return getButtonConfigs(dtlInstCd, prgrsSttsComCd, atrzSeComCdList, {
+ return getButtonConfigs(dtlInstCd, prgrsSttsComCd, effectiveAtrzSeComCdList, {
hasPendingApprovalRequest: needsElaprPrgrsCheck ? hasPendingApprovalRequest : undefined,
hasCompletedDraft: needsPwrkDraftCheck ? hasCompletedDraft : undefined,
canRetryFileVrfc: needsAiAutoLatest ? canRetryFileVrfc : undefined,
canRetryDraftGen: needsAiAutoLatest ? canRetryDraftGen : undefined,
canRetryCostVrfc: needsAiAutoLatest ? canRetryCostVrfc : undefined,
+ isForkJoin,
});
}, [
- atrzSeComCdList,
canRetryCostVrfc,
canRetryDraftGen,
canRetryFileVrfc,
dtlInstCd,
+ effectiveAtrzSeComCdList,
hasCompletedDraft,
hasPendingApprovalRequest,
isAiAutoLatestLoading,
isElaprDocPrgrsLoading,
+ isForkJoin,
isPwrkCnsltnLoading,
isRvwLoginUserLoading,
needsAiAutoLatest,
@@ -234,7 +245,7 @@ function FloatingActionButtons({
isRegister && actionButtons.some((button) => button === FNRS_CNSLTN_VIEW_BUTTON_ACTION.strg);
const canDmndSplmntInPwrkCnsltnDoc =
prgrsSttsComCd === "RK" &&
- atrzSeComCdList.includes("ATRZ02") &&
+ effectiveAtrzSeComCdList.includes("ATRZ02") &&
actionButtons.some((button) => button === FNRS_CNSLTN_VIEW_BUTTON_ACTION.dmndSplmnt);
function handleGoToList() {
@@ -817,7 +828,7 @@ function FloatingActionButtons({
>
{isForkJoin
? userPendingBranchSeCd === "TOTAL_AGG"
- ? "결재 (환경청에 최종회신)"
+ ? "결재 (환경청에 회신)"
: "결재 (병합에 회신)"
: "결재(회신)"}
@@ -877,7 +888,7 @@ function FloatingActionButtons({