Refine lifecycle detail modal totals and project detail popup layout
This commit is contained in:
@@ -1920,6 +1920,7 @@
|
||||
const [companyAccountDetailModal, setCompanyAccountDetailModal] = useState(null);
|
||||
const [companyAccountDetailModalLoading, setCompanyAccountDetailModalLoading] = useState(false);
|
||||
const [lifecycleBreakdownModal, setLifecycleBreakdownModal] = useState(null);
|
||||
const [lifecycleProjectTotalModal, setLifecycleProjectTotalModal] = useState(null);
|
||||
const [lifecycleAccountDetailModal, setLifecycleAccountDetailModal] = useState(null);
|
||||
const [lifecycleAccountDetailModalLoading, setLifecycleAccountDetailModalLoading] = useState(false);
|
||||
const [lifecycleAllocationModal, setLifecycleAllocationModal] = useState(null);
|
||||
@@ -5389,7 +5390,28 @@
|
||||
|
||||
<div style={{ display: "grid", gap: 18, marginTop: 18 }}>
|
||||
<section className="panel" style={{ padding: 16 }}>
|
||||
<div style={{ fontSize: 16, fontWeight: 700 }}>프로젝트별 금액</div>
|
||||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", gap: 12 }}>
|
||||
<div style={{ fontSize: 16, fontWeight: 700 }}>프로젝트별 금액</div>
|
||||
<button
|
||||
type="button"
|
||||
className="button-muted"
|
||||
style={{ height: 30, padding: "0 10px", borderRadius: 9, fontSize: 12 }}
|
||||
onClick={() => {
|
||||
const allocationAccount = (lifecycleBreakdownModal.accounts || []).find(
|
||||
(acc) => Array.isArray(acc.allocation_details) && acc.allocation_details.length
|
||||
) || (lifecycleBreakdownModal.accounts || [])[0] || {};
|
||||
setLifecycleProjectTotalModal({
|
||||
label: lifecycleBreakdownModal.label || "",
|
||||
total_amount: Number(lifecycleBreakdownModal.expense_supply || 0),
|
||||
projects: Array.isArray(lifecycleBreakdownModal.projects) ? lifecycleBreakdownModal.projects.map((project) => ({ ...project })) : [],
|
||||
allocation_mode: allocationAccount.allocation_mode || "",
|
||||
allocation_details: Array.isArray(allocationAccount.allocation_details) ? allocationAccount.allocation_details.map((row) => ({ ...row })) : [],
|
||||
});
|
||||
}}
|
||||
>
|
||||
상세보기
|
||||
</button>
|
||||
</div>
|
||||
<div className="subtle" style={{ marginTop: 6 }}>연결된 프로젝트들 중 이 항목에 반영된 지출 금액입니다.</div>
|
||||
<div style={{ display: "grid", gap: 10, marginTop: 12 }}>
|
||||
{(lifecycleBreakdownModal.projects || []).length ? (
|
||||
@@ -6824,7 +6846,13 @@
|
||||
<div style={{ display: "grid", gridTemplateColumns: "repeat(3, minmax(0, 1fr))", gap: 12, marginTop: 16 }}>
|
||||
<div className="mini-card">
|
||||
<div className="subtle">지출 합계</div>
|
||||
<div className="summary-value" style={{ marginTop: 6 }}>{fmt(lifecycleAccountDetailModal.detail.summary.expense_supply_sum || 0)}원</div>
|
||||
<div className="summary-value" style={{ marginTop: 6 }}>
|
||||
{fmt(
|
||||
Number(lifecycleAccountDetailModal.allocation_result_amount || 0) > 0
|
||||
? Number(lifecycleAccountDetailModal.allocation_result_amount || 0)
|
||||
: Number(lifecycleAccountDetailModal.detail.summary.expense_supply_sum || 0)
|
||||
)}원
|
||||
</div>
|
||||
</div>
|
||||
<div className="mini-card">
|
||||
<div className="subtle">거래 건수</div>
|
||||
@@ -7000,6 +7028,84 @@
|
||||
</div>
|
||||
)}
|
||||
|
||||
{lifecycleProjectTotalModal && (
|
||||
<div className="modal-backdrop" onClick={() => setLifecycleProjectTotalModal(null)}>
|
||||
<div
|
||||
className="modal-panel modal-panel-wide"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
style={{ width: "min(980px, calc(100vw - 32px))", maxHeight: "min(760px, calc(100vh - 32px))", overflow: "auto" }}
|
||||
>
|
||||
<div style={{ display: "flex", justifyContent: "space-between", gap: 16, alignItems: "flex-start" }}>
|
||||
<div>
|
||||
<div style={{ fontSize: 20, fontWeight: 700 }}>{lifecycleProjectTotalModal.label || "전체"} 프로젝트별 상세</div>
|
||||
<div className="subtle" style={{ marginTop: 6 }}>연결 프로젝트 기준 전체 금액 내역입니다.</div>
|
||||
</div>
|
||||
<button className="button-muted" onClick={() => setLifecycleProjectTotalModal(null)}>닫기</button>
|
||||
</div>
|
||||
<div className="mini-card" style={{ marginTop: 14 }}>
|
||||
<div className="subtle">합계 금액</div>
|
||||
<div className="summary-value" style={{ marginTop: 6 }}>{fmt(lifecycleProjectTotalModal.total_amount || 0)}원</div>
|
||||
</div>
|
||||
<section className="mini-card" style={{ marginTop: 12 }}>
|
||||
<div style={{ fontSize: 16, fontWeight: 700 }}>배부 계산식</div>
|
||||
<div className="subtle" style={{ marginTop: 6 }}>본사관리비 배부원천 x (프로젝트 기준값 / 전체 기준값)</div>
|
||||
<div className="subtle" style={{ marginTop: 2 }}>
|
||||
기준값: {(lifecycleProjectTotalModal.allocation_mode || "") === "income_ratio" ? "프로젝트 입금 / 전체입금" : "프로젝트 지출 / 전체지출"}
|
||||
</div>
|
||||
<div className="subtle" style={{ marginTop: 8, lineHeight: 1.55 }}>
|
||||
{(Array.isArray(lifecycleProjectTotalModal.allocation_details) && lifecycleProjectTotalModal.allocation_details.length
|
||||
? lifecycleProjectTotalModal.allocation_details
|
||||
: []
|
||||
).map((row, idx) => {
|
||||
const sourceAmount = Number(row.source_amount || 0);
|
||||
const allocatedAmount = Number(row.allocated_amount || 0);
|
||||
const projectBasisAmount = Number(row.display_project_basis_amount ?? row.project_basis_amount ?? 0);
|
||||
const totalBasisAmount = Number(row.display_total_basis_amount ?? row.total_basis_amount ?? 0);
|
||||
return (
|
||||
<div key={`lifecycle-total-alloc-${idx}`}>
|
||||
{((row.year_month || "").slice(0, 4) || "-")}년 · {fmt(sourceAmount)}원 x ({fmt(projectBasisAmount)}원 / {fmt(totalBasisAmount)}원) = {fmt(allocatedAmount)}원
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{!((lifecycleProjectTotalModal.allocation_details || []).length) && (
|
||||
<div>표시할 배부 계산식이 없습니다.</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
<div style={{ display: "grid", gap: 10, marginTop: 14 }}>
|
||||
{(lifecycleProjectTotalModal.projects || []).length ? (
|
||||
(lifecycleProjectTotalModal.projects || []).map((item) => (
|
||||
<div
|
||||
key={`lifecycle-total-project-${item.project_code}`}
|
||||
style={{
|
||||
textAlign: "left",
|
||||
border: "1px solid var(--line)",
|
||||
borderRadius: 14,
|
||||
background: "white",
|
||||
padding: "12px 14px",
|
||||
display: "grid",
|
||||
gridTemplateColumns: "minmax(220px, 1fr) minmax(160px, 0.45fr)",
|
||||
gap: 12,
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<div style={{ fontWeight: 700 }}>{item.project_name || "(이름없음)"}</div>
|
||||
<div className="subtle" style={{ marginTop: 4 }}>
|
||||
{item.project_code || "-"} · {item.project_type || "미지정"} · {item.construction_family || "종류미지정"} · {item.construction_method || "공법미지정"}
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ textAlign: "right", fontWeight: 700 }}>{fmt(item.expense_supply || 0)}원</div>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<div className="empty-state">표시할 프로젝트가 없습니다.</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{lifecycleAllocationModal && (
|
||||
<div className="modal-backdrop" onClick={() => setLifecycleAllocationModal(null)}>
|
||||
<div className="modal-panel" onClick={(e) => e.stopPropagation()} style={{ width: "min(560px, calc(100vw - 24px))" }}>
|
||||
|
||||
Reference in New Issue
Block a user