[st frontend] 상세 페이지 수정 작업
This commit is contained in:
@@ -1220,7 +1220,7 @@ function CnfmRegistPage() {
|
||||
|
||||
{/* ── 필수 첨부파일 ── */}
|
||||
<div className="cnfm-card p-4">
|
||||
<h3 className="mb-3 border-b pb-2 text-[1.5rem] font-bold text-gray-700">첨부파일</h3>
|
||||
<h3 className="mb-3 border-b pb-2 text-[1.5rem] font-bold text-gray-700">필수 첨부파일</h3>
|
||||
<div className="cnfm-table-wrap">
|
||||
<table className="cnfm-table">
|
||||
<thead>
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
"use client";
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any, import/order */
|
||||
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { Button } from "@common/components";
|
||||
|
||||
import { InstlSncnApi } from "@/entities/instl-sncn";
|
||||
import { dayjs } from "@/shared/lib";
|
||||
import { PROXY_HOST } from "@/shared/config";
|
||||
|
||||
import "./cnfm-page.css";
|
||||
|
||||
@@ -25,15 +28,30 @@ function CnfmViewPage({ id }: { id: string }) {
|
||||
return <div className="mt-6 text-[1.4rem]">상세 정보를 찾을 수 없습니다.</div>;
|
||||
}
|
||||
|
||||
const data = query.data;
|
||||
const data = query.data as any;
|
||||
|
||||
// support API shape where payload includes detDto + lists
|
||||
const det = data.detDto ?? data;
|
||||
const bizSclList = data.bizSclList ?? [];
|
||||
const bizCstList = data.bizCstList ?? [];
|
||||
const cklstResultList = data.cklstResultList ?? [];
|
||||
const esntlFileList = data.esntlFileList ?? [];
|
||||
const etcFileList = data.etcFileList ?? [];
|
||||
|
||||
const fmt = (v: number | null | undefined) =>
|
||||
typeof v === "number" ? v.toLocaleString() : v === null || v === undefined ? "" : String(v);
|
||||
|
||||
const indentPx = (indNm: string | undefined) => {
|
||||
if (!indNm) return 0;
|
||||
const spaces = indNm.length - indNm.trimStart().length;
|
||||
return (spaces / 4) * 16;
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mt-6 space-y-4">
|
||||
<div className="cnfm-card p-4">
|
||||
<h2 className="cnfm-section-title">설치인가 상세보기</h2>
|
||||
<p className="mt-2 text-[1.3rem] text-gray-600">
|
||||
문서번호: <strong>{data.instlSncnDocNo}</strong>
|
||||
</p>
|
||||
<p className="mt-2 text-[1.3rem] text-gray-600">문서번호: <strong>{det.instlSncnDocNo}</strong></p>
|
||||
</div>
|
||||
|
||||
<div className="cnfm-card p-4">
|
||||
@@ -42,27 +60,25 @@ function CnfmViewPage({ id }: { id: string }) {
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>사업명</th>
|
||||
<td>{data.bizNm || "-"}</td>
|
||||
<td>{det.bizNm || "-"}</td>
|
||||
<th>업무구분</th>
|
||||
<td>{data.taskSeCdNm || data.taskSeComCd || "-"}</td>
|
||||
<td>{det.taskSeCdNm || det.taskSeComCd || "-"}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>사업기간</th>
|
||||
<td>
|
||||
{(data.bizBgngYr || "-") + " ~ " + (data.bizEndYr || "-")}
|
||||
</td>
|
||||
<td>{(det.bizBgngYr || "-") + " ~ " + (det.bizEndYr || "-")}</td>
|
||||
<th>진행상태</th>
|
||||
<td>{data.prgrsSttsCdNm || data.prgrsSttsComCd || "-"}</td>
|
||||
<td>{det.prgrsSttsCdNm || det.prgrsSttsComCd || "-"}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>행정동ID</th>
|
||||
<td>{data.dongId || "-"}</td>
|
||||
<td>{det.dongId || "-"}</td>
|
||||
<th>예산사업코드</th>
|
||||
<td>{data.bgtBizCd || "-"}</td>
|
||||
<td>{det.bgtBizCd || "-"}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>사업내용</th>
|
||||
<td colSpan={3}>{data.bizCn || "-"}</td>
|
||||
<td colSpan={3}>{det.bizCn || "-"}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -74,27 +90,27 @@ function CnfmViewPage({ id }: { id: string }) {
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>신청자명</th>
|
||||
<td>{data.aplcntNm || "-"}</td>
|
||||
<td>{det.aplcntNm || "-"}</td>
|
||||
<th>신청자 연락처</th>
|
||||
<td>{data.aplcntMblTelno || "-"}</td>
|
||||
<td>{det.aplcntMblTelno || "-"}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>신청자 소속</th>
|
||||
<td>{data.aplcntOgdpNm || "-"}</td>
|
||||
<td>{det.aplcntOgdpNm || "-"}</td>
|
||||
<th>신청자 이메일</th>
|
||||
<td>{data.aplcntEmlAddr || "-"}</td>
|
||||
<td>{det.aplcntEmlAddr || "-"}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>설계자명</th>
|
||||
<td>{data.dsgnrNm || "-"}</td>
|
||||
<td>{det.dsgnrNm || "-"}</td>
|
||||
<th>설계자 연락처</th>
|
||||
<td>{data.dsgnrTelno || "-"}</td>
|
||||
<td>{det.dsgnrTelno || "-"}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>설계자 소속</th>
|
||||
<td>{data.dsgnrOgdpNm || "-"}</td>
|
||||
<td>{det.dsgnrOgdpNm || "-"}</td>
|
||||
<th>설계자 이메일</th>
|
||||
<td>{data.dsgnrEmlAddr || "-"}</td>
|
||||
<td>{det.dsgnrEmlAddr || "-"}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -106,20 +122,200 @@ function CnfmViewPage({ id }: { id: string }) {
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>등록일시</th>
|
||||
<td>{data.regDt ? dayjs(data.regDt).format("YYYY-MM-DD HH:mm:ss") : "-"}</td>
|
||||
<td>{det.regDt ? dayjs(det.regDt).format("YYYY-MM-DD HH:mm:ss") : "-"}</td>
|
||||
<th>수정일시</th>
|
||||
<td>{data.mdfcnDt ? dayjs(data.mdfcnDt).format("YYYY-MM-DD HH:mm:ss") : "-"}</td>
|
||||
<td>{det.mdfcnDt ? dayjs(det.mdfcnDt).format("YYYY-MM-DD HH:mm:ss") : "-"}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>등록자명</th>
|
||||
<td>{data.rgtrNm || "-"}</td>
|
||||
<td>{det.rgtrNm || "-"}</td>
|
||||
<th>첨부파일그룹ID</th>
|
||||
<td>{data.atchFileGroupId || "-"}</td>
|
||||
<td>{det.atchFileGroupId || "-"}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{/* 사업규모 */}
|
||||
<div className="cnfm-card p-4">
|
||||
<h3 className="mb-3 border-b pb-2 text-[1.5rem] font-bold text-gray-700">사업규모</h3>
|
||||
<div className="cnfm-table-wrap">
|
||||
<table className="cnfm-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="w-[30rem]">구분</th>
|
||||
<th>기본계획(A)</th>
|
||||
<th>예산반영(B)</th>
|
||||
<th>금회설계시(C)</th>
|
||||
<th>증감(C-B)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{bizSclList.length === 0 ? (
|
||||
<tr>
|
||||
<td colSpan={5} className="cnfm-td-empty">조회된 사업규모 항목이 없습니다.</td>
|
||||
</tr>
|
||||
) : (
|
||||
bizSclList.map((node: any) => {
|
||||
const pl = indentPx(node.indCnstpSeCdNm);
|
||||
const a = Number(node.bscPlanQty) || 0;
|
||||
const b = Number(node.bgtRfltQty) || 0;
|
||||
const c = Number(node.tstmDesignQty) || 0;
|
||||
const diff = c - b;
|
||||
return (
|
||||
<tr key={node.cnstpSeCd} className={node.treeLevel === 1 ? "bg-gray-50 font-semibold" : ""}>
|
||||
<td className="bg-gray-50 pl-2 text-left" style={{ paddingLeft: `${pl + 8}px` }}>{node.cnstpSeCdNm}</td>
|
||||
<td><div className="text-right">{fmt(a)}</div></td>
|
||||
<td><div className="text-right">{fmt(b)}</div></td>
|
||||
<td><div className="text-right">{fmt(c)}</div></td>
|
||||
<td><div className="text-right">{diff > 0 ? `+${fmt(diff)}` : fmt(diff)}</div></td>
|
||||
</tr>
|
||||
);
|
||||
})
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 총사업비 */}
|
||||
<div className="cnfm-card p-4">
|
||||
<h3 className="mb-3 border-b pb-2 text-[1.5rem] font-bold text-gray-700">총사업비 <span className="text-[1.2rem] font-normal text-gray-400">(단위: 백만원)</span></h3>
|
||||
<div className="cnfm-table-wrap">
|
||||
<table className="cnfm-table w-full table-fixed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colSpan={2} className="w-[30rem]">구분</th>
|
||||
<th>예산반영(A)</th>
|
||||
<th>표준사업비(B)</th>
|
||||
<th>금회설계시(C)</th>
|
||||
<th>증감</th>
|
||||
<th>%</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{bizCstList.map((node: any) => {
|
||||
const pl = indentPx(node.indAcntgSeCdNm);
|
||||
const a = Number(node.bscPlanAmt) || 0;
|
||||
const b = Number(node.bgtRfltAmt) || 0;
|
||||
const c = Number(node.tstmDesignAmt) || 0;
|
||||
const diff = c - b;
|
||||
|
||||
return (
|
||||
<tr key={node.acntgSeCd} className={node.treeLevel === 1 ? "bg-blue-50 font-bold" : node.treeLevel === 2 ? "bg-gray-100 font-semibold" : ""}>
|
||||
{node.treeLevel <= 2 ? (
|
||||
<td colSpan={2} className="pl-2 text-left">{node.acntgSeCdNm}</td>
|
||||
) : (
|
||||
<>
|
||||
<td className="w-[4rem]"></td>
|
||||
<td className="bg-gray-50 text-left" style={{ paddingLeft: `${pl + 8}px` }}>{node.acntgSeCdNm}</td>
|
||||
</>
|
||||
)}
|
||||
|
||||
<td><div className="text-right">{fmt(a)}</div></td>
|
||||
<td><div className="text-right">{fmt(b)}</div></td>
|
||||
<td><div className="text-right">{fmt(c)}</div></td>
|
||||
<td><div className="text-right">{diff > 0 ? `+${fmt(diff)}` : fmt(diff)}</div></td>
|
||||
<td><div className="text-right">{b !== 0 ? `${Math.round((diff / b) * 100)}%` : "-"}</div></td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 체크리스트 */}
|
||||
<div className="cnfm-card p-4">
|
||||
<h3 className="text-[1.5rem] font-bold text-gray-700">체크리스트</h3>
|
||||
<div className="cnfm-table-wrap mt-3">
|
||||
<table className="cnfm-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="w-[20rem]">검토항목</th>
|
||||
<th>주요 검토내용</th>
|
||||
<th>검토 결과</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{cklstResultList.length === 0 ? (
|
||||
<tr>
|
||||
<td colSpan={3} className="cnfm-td-empty">조회된 체크리스트 항목이 없습니다.</td>
|
||||
</tr>
|
||||
) : (
|
||||
cklstResultList.map((row: any) => (
|
||||
<tr key={`${row.cklstSn}_${row.cklstRvwSn}`}>
|
||||
<td className="text-center text-[1.2rem]">{row.cklstArtclNm}</td>
|
||||
<td className="!text-left pl-2 text-[1.2rem] text-gray-600" style={{ paddingLeft: `${Math.max(0, row.treeLevel - 1) * 16 + 8}px` }}>{row.treeLevel > 1 ? "└ " : ""}{row.rvwCn}</td>
|
||||
<td className="text-center text-[1.2rem]">{row.bchckUseYn === "Y" ? (row.rvwRsltAnmlyYn === "Y" ? "예" : row.rvwRsltAnmlyYn === "N" ? "아니오" : "-") : "-"}</td>
|
||||
</tr>
|
||||
))
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 첨부파일 */}
|
||||
<div className="cnfm-card p-4">
|
||||
<h3 className="mb-3 border-b pb-2 text-[1.5rem] font-bold text-gray-700">필수 첨부파일</h3>
|
||||
<div className="cnfm-table-wrap">
|
||||
<table className="cnfm-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>필수 자료명</th>
|
||||
<th>파일형식</th>
|
||||
<th>파일</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{esntlFileList.length === 0 ? (
|
||||
<tr>
|
||||
<td colSpan={3} className="cnfm-td-empty">조회된 필수 첨부파일 항목이 없습니다.</td>
|
||||
</tr>
|
||||
) : (
|
||||
esntlFileList.map((f: any) => (
|
||||
<tr key={f.esntlAtchFileId}>
|
||||
<td className="pl-2">
|
||||
<div className="w-full text-left">
|
||||
{f.esntlAtchFileNm}
|
||||
{f.esntlAtchYn === "Y" ? <span className="ml-1 text-red-500">*</span> : null}
|
||||
</div>
|
||||
</td>
|
||||
<td>{(f.esntlAtchFileRmrk || "").replaceAll(",", "/") || "-"}</td>
|
||||
<td>
|
||||
{f.atflCd ? (
|
||||
<a className="text-blue-600" href={`${PROXY_HOST}/attach-service/api/v1/atflcd/download/${f.atflCd}`} target="_blank" rel="noreferrer">{f.orgnlFileNm || "다운로드"}</a>
|
||||
) : (
|
||||
<span className="text-gray-500">첨부없음</span>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h4 className="mt-4 mb-2 text-[1.25rem] font-semibold">기타 첨부파일</h4>
|
||||
{etcFileList.length === 0 ? (
|
||||
<div className="text-gray-500">등록된 기타첨부파일이 없습니다.</div>
|
||||
) : (
|
||||
<ul className="space-y-2">
|
||||
{etcFileList.map((f: any) => (
|
||||
<li key={f.atflId}>
|
||||
{f.orgnlFileNm ? (
|
||||
<a className="text-blue-600" href={`${PROXY_HOST}/attach-service/api/v1/atflcd/download/${f.atflCd}`} target="_blank" rel="noreferrer">{f.orgnlFileNm}</a>
|
||||
) : (
|
||||
<span className="text-gray-700">{f.physFileNm || f.atflId}</span>
|
||||
)}
|
||||
<span className="ml-2 text-gray-500">{f.atflFlieSz ? `(${Math.round(f.atflFlieSz / 1024)}KB)` : ""}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="cnfm-action-row">
|
||||
<Button color="white" onClick={() => router.push("/instl-sncn")}>목록</Button>
|
||||
<Button onClick={() => router.push(`/instl-sncn/${id}/modify`)}>수정</Button>
|
||||
|
||||
Reference in New Issue
Block a user