feat: 재원협의&실무협의서 로직 사이클
This commit is contained in:
@@ -71,8 +71,8 @@ API 컬럼은 [ref-endpoint.md](./ref-endpoint.md)와 동일.
|
||||
| 34 | 상세 | USER01 | 승인자 | `RK` | 결재(승인) | `RK` | 다음 결재자 | `process` |
|
||||
| 35 | 상세 | USER01 | 최종승인자 | `RK` | 결재(회신) | `RR` | 환경청 | `process` 최종 |
|
||||
| 36 | 상세 | USER03 | - | `RR` | 실무협의서 관리(조회), 검토결과 회신 | `EP` | 광역 | `tech-review` |
|
||||
| 37 | 작성/상세 | USER04 | - | `EP` | 결과회신 | `TA` | 기초 | `updatePrgrsStts` |
|
||||
| 38 | 상세 | USER05 | - | `TA` | 결과회신 | — | — | **API 없음. 조회** |
|
||||
| 37 | 작성/상세 | USER04 | - | `EP` | 결과회신, 실무협의서 관리(조회) | `TA` | 기초 | `updatePrgrsStts` |
|
||||
| 38 | 상세 | USER05 | - | `TA` | 결과회신, 실무협의서 관리(조회) | — | — | **API 없음. 조회** |
|
||||
|
||||
`SL` 20~22행: 버튼은 직전 상태에 따라 **하나만** 노출. 파일 루프면 [파일보완완료], 그 외 [보완완료].
|
||||
|
||||
@@ -109,13 +109,13 @@ ROLE_USER05
|
||||
"" | SV → 저장, 신청완료, 삭제
|
||||
SL → (직전 ER) 파일보완완료 | (직전 TE|RK) 보완완료
|
||||
RB → 실무협의서 관리, 조치완료
|
||||
TA → 결과회신 (조회)
|
||||
TA → 결과회신 (조회), 실무협의서 관리(조회)
|
||||
|
||||
ROLE_USER04
|
||||
ST → 환경청제출 // 현행 반려(rjct→SV)는 SoT 38행에 없음. 유지 시 별도 합의
|
||||
RM → 지자체회신
|
||||
RC → 조치결과서제출
|
||||
EP → 결과회신
|
||||
EP → 결과회신, 실무협의서 관리(조회)
|
||||
|
||||
ROLE_USER03
|
||||
LE → 결과회신(자체종결), 기술검토 의뢰
|
||||
|
||||
@@ -39,12 +39,15 @@ const ROLE_STATUS_BUTTON_ACTIONS: Record<string, Record<string, FnrsCnsltnViewBu
|
||||
FNRS_CNSLTN_VIEW_BUTTON_ACTION.del,
|
||||
],
|
||||
RB: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng, FNRS_CNSLTN_VIEW_BUTTON_ACTION.actnCmptn],
|
||||
TA: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.fnrsCnsltnAncmnt],
|
||||
TA: [
|
||||
FNRS_CNSLTN_VIEW_BUTTON_ACTION.fnrsCnsltnAncmnt,
|
||||
FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng,
|
||||
],
|
||||
},
|
||||
ROLE_USER04: {
|
||||
ST: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.envoSbmsn, FNRS_CNSLTN_VIEW_BUTTON_ACTION.rjct],
|
||||
RM: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.lclRply],
|
||||
EP: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.sncnAprv],
|
||||
EP: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.sncnAprv, FNRS_CNSLTN_VIEW_BUTTON_ACTION.pwrkCnsltnDocMng],
|
||||
},
|
||||
ROLE_USER03: {
|
||||
LE: [FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwRply, FNRS_CNSLTN_VIEW_BUTTON_ACTION.rqstTechRvw],
|
||||
|
||||
@@ -61,16 +61,25 @@ export const TASK_CODE_LABELS: Record<string, string> = {
|
||||
};
|
||||
|
||||
export const PBADMS_PROGRESS_ORDER = [
|
||||
// LOCAL
|
||||
"SV",
|
||||
"SL",
|
||||
"TA",
|
||||
"ST",
|
||||
"SL",
|
||||
"RB",
|
||||
"EP",
|
||||
"TA",
|
||||
|
||||
// ENV
|
||||
"LE",
|
||||
"TP",
|
||||
"RA",
|
||||
"RR",
|
||||
|
||||
// KECO
|
||||
"ER",
|
||||
"TE",
|
||||
"TB",
|
||||
"EV",
|
||||
"RK",
|
||||
] as const;
|
||||
|
||||
export const ROLE_TO_REVIEW_STEP: Record<string, ReviewStepCode> = {
|
||||
|
||||
@@ -262,18 +262,18 @@ function FloatingActionButtons({
|
||||
router.push("/fnrs-cnsltn");
|
||||
}
|
||||
|
||||
async function handleFnrsCnsltnAncmntClick() {
|
||||
const payload: DocPrgrsUpdateRequestDto = {
|
||||
docNo,
|
||||
docSeComCd,
|
||||
prgrsSttsComCd: "TB",
|
||||
};
|
||||
await executeAction({
|
||||
action: FNRS_CNSLTN_VIEW_BUTTON_ACTION.fnrsCnsltnAncmnt,
|
||||
request: payload,
|
||||
successMessage: "고시되었습니다.",
|
||||
});
|
||||
}
|
||||
// async function handleFnrsCnsltnAncmntClick() {
|
||||
// const payload: DocPrgrsUpdateRequestDto = {
|
||||
// docNo,
|
||||
// docSeComCd,
|
||||
// prgrsSttsComCd: "TB",
|
||||
// };
|
||||
// await executeAction({
|
||||
// action: FNRS_CNSLTN_VIEW_BUTTON_ACTION.fnrsCnsltnAncmnt,
|
||||
// request: payload,
|
||||
// successMessage: "고시되었습니다.",
|
||||
// });
|
||||
// }
|
||||
|
||||
async function handleEnvoSbmsnClick() {
|
||||
const payload: DocPrgrsUpdateRequestDto = {
|
||||
@@ -323,7 +323,7 @@ function FloatingActionButtons({
|
||||
await executeAction({
|
||||
action: FNRS_CNSLTN_VIEW_BUTTON_ACTION.sncnAprv,
|
||||
request: payload,
|
||||
successMessage: "인가승인되었습니다.",
|
||||
successMessage: "결과 회신이 완료되었습니다.",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -570,11 +570,11 @@ function FloatingActionButtons({
|
||||
삭제
|
||||
</Button>
|
||||
)}
|
||||
{shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.fnrsCnsltnAncmnt) && (
|
||||
{/* {shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.fnrsCnsltnAncmnt) && (
|
||||
<Button onClick={handleFnrsCnsltnAncmntClick} disabled={isProcessing}>
|
||||
재원협의 고시
|
||||
</Button>
|
||||
)}
|
||||
)} */}
|
||||
{shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.envoSbmsn) && (
|
||||
<Button onClick={handleEnvoSbmsnClick} disabled={isProcessing}>
|
||||
환경청 제출
|
||||
@@ -592,12 +592,12 @@ function FloatingActionButtons({
|
||||
)}
|
||||
{shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.sncnAprv) && (
|
||||
<Button onClick={handleSncnAprvClick} disabled={isProcessing}>
|
||||
인가승인
|
||||
결과 회신
|
||||
</Button>
|
||||
)}
|
||||
{shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rvwRply) && (
|
||||
<Button color="green" onClick={handleRvwRplyClick} disabled={isProcessing}>
|
||||
{prgrsSttsComCd === "RR" ? "검토결과 회신" : "재원협의 결과 회신"}
|
||||
{prgrsSttsComCd === "RR" ? "검토 결과 회신" : "재원협의 결과 회신"}
|
||||
</Button>
|
||||
)}
|
||||
{shouldShowButton(FNRS_CNSLTN_VIEW_BUTTON_ACTION.rqstTechRvw) && (
|
||||
@@ -722,13 +722,8 @@ function FloatingActionButtons({
|
||||
open={activeDialog === "pwrkCnsltnDocMng"}
|
||||
fnrsCnsltnDocNo={docNo}
|
||||
atrzSeComCdList={atrzSeComCdList}
|
||||
canSave={
|
||||
prgrsSttsComCd === "RA" ||
|
||||
prgrsSttsComCd === "RR" ||
|
||||
(needsElaprPrgrsCheck && !hasPendingApprovalRequest)
|
||||
? false
|
||||
: undefined
|
||||
}
|
||||
prgrsSttsComCd={prgrsSttsComCd}
|
||||
canSave={needsElaprPrgrsCheck && !hasPendingApprovalRequest ? false : undefined}
|
||||
onClose={() => setActiveDialog(null)}
|
||||
/>
|
||||
|
||||
|
||||
@@ -43,10 +43,13 @@ const PWRK_ATCH_FILE_KEY_PREFIX = "pwrk-cnsltn-doc::";
|
||||
|
||||
const APPROVER_ATRZ_SE_COM_CDS = new Set(["ATRZ03", "ATRZ99"]);
|
||||
|
||||
const VIEW_ONLY_PRGRS_STTS_COM_CDS = new Set(["RA", "RR", "EP", "TA"]);
|
||||
|
||||
interface PwrkCnsltnDocMngDialogProps {
|
||||
open: boolean;
|
||||
fnrsCnsltnDocNo: string;
|
||||
atrzSeComCdList: string[];
|
||||
prgrsSttsComCd: string;
|
||||
canSave?: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
@@ -66,6 +69,7 @@ function PwrkCnsltnDocMngDialog({
|
||||
open,
|
||||
fnrsCnsltnDocNo,
|
||||
atrzSeComCdList,
|
||||
prgrsSttsComCd,
|
||||
canSave: canSaveProp,
|
||||
onClose,
|
||||
}: PwrkCnsltnDocMngDialogProps) {
|
||||
@@ -73,7 +77,7 @@ function PwrkCnsltnDocMngDialog({
|
||||
const alert = useAlertStore((state) => state.setMessage);
|
||||
const [atchFileGroupId, setAtchFileGroupId] = useState("");
|
||||
const [uploadedFiles, setUploadedFiles] = useState<UploadedAtchFile[]>([]);
|
||||
const [isPjtcoAjmtTableOpen, setIsPjtcoAjmtTableOpen] = useState(true);
|
||||
const [isPjtcoAjmtTableOpen, setIsPjtcoAjmtTableOpen] = useState(false);
|
||||
|
||||
const {
|
||||
data: pwrkCnsltnData,
|
||||
@@ -253,8 +257,9 @@ function PwrkCnsltnDocMngDialog({
|
||||
}
|
||||
|
||||
const isAnyAtchUploading = uploadedFiles.some((item) => isUploading[item.fileKey]);
|
||||
const viewOnly = VIEW_ONLY_PRGRS_STTS_COM_CDS.has(prgrsSttsComCd);
|
||||
const canSaveByAtrz = !atrzSeComCdList.some((code) => APPROVER_ATRZ_SE_COM_CDS.has(code));
|
||||
const canSave = canSaveProp ?? canSaveByAtrz;
|
||||
const canSave = !viewOnly && (canSaveProp ?? canSaveByAtrz);
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={handleOpenChange}>
|
||||
@@ -289,39 +294,41 @@ function PwrkCnsltnDocMngDialog({
|
||||
onDownload={handleDownload}
|
||||
/>
|
||||
</div>
|
||||
{isPjtcoAjmtTableOpen ? (
|
||||
<section className="flex h-[calc(64vh+4rem)] w-0 flex-[0.4] flex-col overflow-hidden rounded-md border border-border">
|
||||
<header className="flex items-center justify-between gap-2 border-b border-border px-3 py-2">
|
||||
<h3 className="text-xl font-semibold">금액검증결과</h3>
|
||||
<button
|
||||
type="button"
|
||||
className="rounded-sm border border-border p-2 hover:opacity-90"
|
||||
onClick={() => setIsPjtcoAjmtTableOpen(false)}
|
||||
aria-label="접기"
|
||||
>
|
||||
<PanelRightClose className="size-6" />
|
||||
</button>
|
||||
</header>
|
||||
<div className="min-h-0 flex-1 overflow-y-auto">
|
||||
<PwrkCnsltnDocPjtcoAjmtTable
|
||||
rows={pjtcoAjmtPage?.content ?? []}
|
||||
isLoading={isPjtcoAjmtLoading}
|
||||
isError={isPjtcoAjmtError}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
className="flex items-center gap-1 self-start rounded-sm border border-border px-1 py-2 hover:opacity-90"
|
||||
style={{ writingMode: "vertical-rl" }}
|
||||
onClick={() => setIsPjtcoAjmtTableOpen(true)}
|
||||
aria-label="펼치기"
|
||||
>
|
||||
<PanelRightOpen className="size-5" />
|
||||
<span className="text-xl tracking-wide">금액검증결과</span>
|
||||
</button>
|
||||
)}
|
||||
{pjtcoAjmtPage?.content?.length ? (
|
||||
isPjtcoAjmtTableOpen ? (
|
||||
<section className="flex h-[calc(64vh+4rem)] w-0 flex-[0.4] flex-col overflow-hidden rounded-md border border-border">
|
||||
<header className="flex items-center justify-between gap-2 border-b border-border px-3 py-2">
|
||||
<h3 className="text-xl font-semibold">금액검증결과</h3>
|
||||
<button
|
||||
type="button"
|
||||
className="rounded-sm border border-border p-2 hover:opacity-90"
|
||||
onClick={() => setIsPjtcoAjmtTableOpen(false)}
|
||||
aria-label="접기"
|
||||
>
|
||||
<PanelRightClose className="size-6" />
|
||||
</button>
|
||||
</header>
|
||||
<div className="min-h-0 flex-1 overflow-y-auto">
|
||||
<PwrkCnsltnDocPjtcoAjmtTable
|
||||
rows={pjtcoAjmtPage?.content ?? []}
|
||||
isLoading={isPjtcoAjmtLoading}
|
||||
isError={isPjtcoAjmtError}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
className="flex items-center gap-1 self-start rounded-sm border border-border px-1 py-2 hover:opacity-90"
|
||||
style={{ writingMode: "vertical-rl" }}
|
||||
onClick={() => setIsPjtcoAjmtTableOpen(true)}
|
||||
aria-label="펼치기"
|
||||
>
|
||||
<PanelRightOpen className="size-5" />
|
||||
<span className="text-xl tracking-wide">금액검증결과</span>
|
||||
</button>
|
||||
)
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user