Stabilize project flows and reporting

This commit is contained in:
b17301
2026-04-09 21:01:21 +09:00
parent f2d86cd840
commit 9aaae5b820
11 changed files with 5118 additions and 626 deletions
+24 -40
View File
@@ -228,16 +228,6 @@
</div>
</div>
<div class="chart-shell" style="margin-bottom: 16px;">
<div class="legend-box" style="justify-content:flex-start;">
<span class="legend-item"><span class="legend-swatch" style="background:#111827;"></span>계약 프로젝트 {{ import_sync_summary.contract_project_count or 0 }}건</span>
<span class="legend-item"><span class="legend-swatch" style="background:#0f766e;"></span>청구 프로젝트 {{ import_sync_summary.billing_project_count or 0 }}건</span>
<span class="legend-item"><span class="legend-swatch" style="background:#f59e0b;"></span>변경계약 검토 {{ import_sync_summary.review_needed_count or 0 }}건</span>
<span class="legend-item"><span class="legend-swatch" style="background:#1d4ed8;"></span>한맥 계약합계 {{ "{:,.0f}".format(import_sync_summary.total_hanmac_contract_amount or 0) }}</span>
<span class="legend-item"><span class="legend-swatch" style="background:#7c3aed;"></span>청구 수금합계 {{ "{:,.0f}".format(import_sync_summary.total_collected_amount or 0) }}</span>
</div>
</div>
<div class="dashboard-layout">
<section class="dashboard-status-panel">
<div class="dashboard-status-grid">
@@ -285,10 +275,9 @@
</select>
<select id="revenueMetric" aria-label="수금 구성 항목 선택">
<option value="all">전체 항목</option>
<option value="design_revenue">설계</option>
<option value="design_other_revenue">설계 외</option>
<option value="supervision_revenue">감리</option>
<option value="inspection_revenue">점검</option>
{% for option in dashboard_revenue_metric_options %}
<option value="{{ option.item_key }}">{{ option.label }}</option>
{% endfor %}
</select>
</div>
</div>
@@ -314,10 +303,9 @@
</select>
<select id="expenseMetric" aria-label="지출 구성 항목 선택">
<option value="all">전체 항목</option>
<option value="cost_sum">원가</option>
<option value="sga_sum">판관비</option>
<option value="labor_sum">원가인건비</option>
<option value="outsourcing_sum">원가외주비</option>
{% for option in dashboard_expense_metric_options %}
<option value="{{ option.item_key }}">{{ option.label }}</option>
{% endfor %}
</select>
</div>
</div>
@@ -339,35 +327,31 @@
const revenueYearly = {{ project_revenue_mix_yearly | tojson }};
const revenueMonthly = {{ project_revenue_mix_monthly | tojson }};
const pageSelectedYear = {{ overview_selected_year | tojson }};
const dashboardRevenueMetricOptions = {{ dashboard_revenue_metric_options | tojson }};
const dashboardExpenseMetricOptions = {{ dashboard_expense_metric_options | tojson }};
const revenuePalette = {
design_revenue: { label: "설계", color: "#4f7cff" },
design_other_revenue: { label: "설계 외", color: "#67c7c9" },
supervision_revenue: { label: "감리", color: "#233a5a" },
inspection_revenue: { label: "점검", color: "#ffb54a" },
};
const revenuePalette = Object.fromEntries(
dashboardRevenueMetricOptions.map((option) => [
option.item_key,
{ label: option.label, color: option.value },
]),
);
const expensePalette = {
cost_sum: { label: "원가", color: "#4f7cff" },
sga_sum: { label: "판관비", color: "#67c7c9" },
labor_sum: { label: "원가인건비", color: "#233a5a" },
outsourcing_sum: { label: "원가외주비", color: "#ffb54a" },
};
const expensePalette = Object.fromEntries(
dashboardExpenseMetricOptions.map((option) => [
option.item_key,
{ label: option.label, color: option.value },
]),
);
const revenueMetricMap = {
all: ["design_revenue", "design_other_revenue", "supervision_revenue", "inspection_revenue"],
design_revenue: ["design_revenue"],
design_other_revenue: ["design_other_revenue"],
supervision_revenue: ["supervision_revenue"],
inspection_revenue: ["inspection_revenue"],
all: dashboardRevenueMetricOptions.map((option) => option.item_key),
...Object.fromEntries(dashboardRevenueMetricOptions.map((option) => [option.item_key, [option.item_key]])),
};
const expenseMetricMap = {
all: ["cost_sum", "sga_sum", "labor_sum", "outsourcing_sum"],
cost_sum: ["cost_sum"],
sga_sum: ["sga_sum"],
labor_sum: ["labor_sum"],
outsourcing_sum: ["outsourcing_sum"],
all: dashboardExpenseMetricOptions.map((option) => option.item_key),
...Object.fromEntries(dashboardExpenseMetricOptions.map((option) => [option.item_key, [option.item_key]])),
};
function formatNumber(value) {