[st frontend] as 사용자 뷰 정보 표시 정리
This commit is contained in:
@@ -9,6 +9,7 @@ import { Button } from "@common/components";
|
||||
import { InstlSncnApi } from "@/entities/instl-sncn";
|
||||
import { dayjs } from "@/shared/lib";
|
||||
import { PROXY_HOST } from "@/shared/config";
|
||||
import { formatFileSize } from "@/shared/lib/file-utils";
|
||||
|
||||
import "./cnfm-page.css";
|
||||
|
||||
@@ -47,6 +48,8 @@ function CnfmViewPage({ id }: { id: string }) {
|
||||
return (spaces / 4) * 16;
|
||||
};
|
||||
|
||||
/* formatFileSize moved to shared lib: @/shared/lib/file-utils */
|
||||
|
||||
return (
|
||||
<div className="mt-6 space-y-4">
|
||||
<div className="cnfm-card p-4">
|
||||
@@ -61,25 +64,26 @@ function CnfmViewPage({ id }: { id: string }) {
|
||||
<tr>
|
||||
<th>사업명</th>
|
||||
<td>{det.bizNm || "-"}</td>
|
||||
<th>업무구분</th>
|
||||
<td>{det.taskSeCdNm || det.taskSeComCd || "-"}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>사업기간</th>
|
||||
<td>{(det.bizBgngYr || "-") + " ~ " + (det.bizEndYr || "-")}</td>
|
||||
<th>진행상태</th>
|
||||
<td>{det.prgrsSttsCdNm || det.prgrsSttsComCd || "-"}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>행정동ID</th>
|
||||
<td>{det.dongId || "-"}</td>
|
||||
<th>예산사업코드</th>
|
||||
<td>{det.bgtBizCd || "-"}</td>
|
||||
<th>사업기간</th>
|
||||
<td>{(det.bizBgngYr || "-") + " ~ " + (det.bizEndYr || "-")}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>사업내용</th>
|
||||
<td colSpan={3}>{det.bizCn || "-"}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>업무구분</th>
|
||||
<td>{det.taskSeCdNm || det.taskSeComCd || "-"}</td>
|
||||
<th>행정동ID</th>
|
||||
<td>{det.dongId || "-"}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>진행상태</th>
|
||||
<td>{det.prgrsSttsCdNm || det.prgrsSttsComCd || "-"}</td>
|
||||
<th>예산사업코드</th>
|
||||
<td>{det.bgtBizCd || "-"}</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -158,16 +162,16 @@ function CnfmViewPage({ id }: { id: string }) {
|
||||
) : (
|
||||
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;
|
||||
const bscPlanQty = Number(node.bscPlanQty) || 0;
|
||||
const budgetReflct = Number(node.bgtRfltQty) || 0;
|
||||
const tstmDesignQty = Number(node.tstmDesignQty) || 0;
|
||||
const diff = tstmDesignQty - budgetReflct;
|
||||
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">{fmt(bscPlanQty)}</div></td>
|
||||
<td><div className="text-right">{fmt(budgetReflct)}</div></td>
|
||||
<td><div className="text-right">{fmt(tstmDesignQty)}</div></td>
|
||||
<td><div className="text-right">{diff > 0 ? `+${fmt(diff)}` : fmt(diff)}</div></td>
|
||||
</tr>
|
||||
);
|
||||
@@ -185,38 +189,70 @@ function CnfmViewPage({ id }: { id: string }) {
|
||||
<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>
|
||||
<th colSpan={2} className="w-[30rem]" rowSpan={2}>
|
||||
구분
|
||||
</th>
|
||||
<th rowSpan={2}>예산반영(A)</th>
|
||||
<th rowSpan={2}>표준사업비(B)</th>
|
||||
<th rowSpan={2}>금회설계시(C)</th>
|
||||
<th colSpan={2}>증감</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th className="w-[12rem]">(C-B)</th>
|
||||
<th className="w-[6rem]">%</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;
|
||||
|
||||
const bscPlanAmt = Number(node.bscPlanAmt) || 0;
|
||||
const budgetReflct = Number(node.bgtRfltAmt) || 0;
|
||||
const tstmDesignAmt = Number(node.tstmDesignAmt) || 0;
|
||||
const diff = tstmDesignAmt - budgetReflct;
|
||||
const showSubIcon = node.treeLevel >= 4;
|
||||
const isLeaf = !bizCstList.some((n: any) => n.upAcntgSeCd === node.acntgSeCd);
|
||||
return (
|
||||
<tr key={node.acntgSeCd} className={node.treeLevel === 1 ? "bg-blue-50 font-bold" : node.treeLevel === 2 ? "bg-gray-100 font-semibold" : ""}>
|
||||
<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
|
||||
className={`bg-gray-50 text-left ${isLeaf ? "text-gray-700" : ""}`}
|
||||
style={{ paddingLeft: `${pl + 8}px` }}
|
||||
>
|
||||
{showSubIcon && <span className="mr-1 text-gray-400">└</span>}
|
||||
{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>
|
||||
<td>
|
||||
<div className="text-right">{fmt(bscPlanAmt)}</div>
|
||||
</td>
|
||||
<td>
|
||||
<div className="text-right">{fmt(budgetReflct)}</div>
|
||||
</td>
|
||||
<td>
|
||||
<div className="text-right">{fmt(tstmDesignAmt)}</div>
|
||||
</td>
|
||||
<td>
|
||||
<div className="text-right">{diff > 0 ? `+${fmt(diff)}` : fmt(diff)}</div>
|
||||
</td>
|
||||
<td>
|
||||
<div className="text-right">{budgetReflct !== 0 ? `${Math.round((diff / budgetReflct) * 100)}%` : "-"}</div>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
@@ -234,7 +270,25 @@ function CnfmViewPage({ id }: { id: string }) {
|
||||
<tr>
|
||||
<th className="w-[20rem]">검토항목</th>
|
||||
<th>주요 검토내용</th>
|
||||
<th>검토 결과</th>
|
||||
<th colSpan={2}>검토 결과(-)</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th />
|
||||
<th />
|
||||
<th className="w-[9rem]">
|
||||
<button
|
||||
type="button"
|
||||
>
|
||||
예
|
||||
</button>
|
||||
</th>
|
||||
<th className="w-[9rem]">
|
||||
<button
|
||||
type="button"
|
||||
>
|
||||
아니오
|
||||
</button>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -243,29 +297,49 @@ function CnfmViewPage({ id }: { id: string }) {
|
||||
<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>
|
||||
))
|
||||
cklstResultList.map((row: any) => {
|
||||
const key = `${row.cklstSn}_${row.cklstRvwSn}`;
|
||||
const hasResult = row.rvwRsltAnmlyYn === "Y" || row.rvwRsltAnmlyYn === "N";
|
||||
const showRadios = row.bchckUseYn === "Y" || hasResult;
|
||||
|
||||
return (
|
||||
<tr key={key}>
|
||||
<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>
|
||||
{!showRadios ? (
|
||||
<>
|
||||
<td className="text-center">-</td>
|
||||
<td className="text-center">-</td>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<td className="text-center">
|
||||
<input type="radio" name={`chk_${key}`} value="Y" checked={row.rvwRsltAnmlyYn === "Y"} disabled />
|
||||
</td>
|
||||
<td className="text-center">
|
||||
<input type="radio" name={`chk_${key}`} value="N" checked={row.rvwRsltAnmlyYn === "N"} disabled />
|
||||
</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>
|
||||
<th>필수 자료명</th>
|
||||
<th>파일명</th>
|
||||
<th className="w-[8rem] text-right">크기</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -282,7 +356,6 @@ function CnfmViewPage({ id }: { id: string }) {
|
||||
{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>
|
||||
@@ -290,30 +363,48 @@ function CnfmViewPage({ id }: { id: string }) {
|
||||
<span className="text-gray-500">첨부없음</span>
|
||||
)}
|
||||
</td>
|
||||
<td className="w-[8rem] text-right"><div className="text-right">{formatFileSize(f.atflFlieSz)}</div></td>
|
||||
</tr>
|
||||
))
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</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 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 className="w-[8rem] text-right">크기</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{etcFileList.length === 0 ? (
|
||||
<tr>
|
||||
<td colSpan={2} className="cnfm-td-empty">등록된 기타첨부파일이 없습니다.</td>
|
||||
</tr>
|
||||
) : (
|
||||
etcFileList.map((f: any) => (
|
||||
<tr key={f.atflId}>
|
||||
<td>
|
||||
{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>
|
||||
)}
|
||||
</td>
|
||||
<td className="w-[8rem] text-right text-gray-500">{formatFileSize(f.atflFlieSz)}</td>
|
||||
</tr>
|
||||
))
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="cnfm-action-row">
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/* Shared file utilities for apps/as */
|
||||
|
||||
/** 파일 크기는 byte 단위로 제공된다고 가정하고 크기에 따라서 KB, MB 단위로 표시 */
|
||||
export const formatFileSize = (bytes?: number | null): string => {
|
||||
if (bytes === null || bytes === undefined) return "-";
|
||||
const b = Number(bytes) || 0;
|
||||
if (b >= 1024 * 1024) return `${(b / 1024 / 1024).toFixed(1)}MB`;
|
||||
if (b >= 1024) return `${Math.round(b / 1024)}KB`;
|
||||
return `${b}B`;
|
||||
};
|
||||
|
||||
export default { formatFileSize };
|
||||
Reference in New Issue
Block a user