From be6a7f5c38d73f88a590ff154f609a7bee74bcc6 Mon Sep 17 00:00:00 2001 From: mac Date: Tue, 16 Jun 2026 14:21:57 +0800 Subject: [PATCH] =?UTF-8?q?v1.7.8=20=E2=80=94=20=E9=A6=96=E9=A1=B5?= =?UTF-8?q?=E6=94=B9=E4=B8=BA3=E8=A1=A8=E6=A0=BC=E5=8D=A1=E7=89=87(?= =?UTF-8?q?=E5=90=88=E5=90=8C/=E7=A1=AE=E6=94=B6/=E6=AF=9B=E5=88=A9)=20+?= =?UTF-8?q?=20=E5=90=88=E5=90=8C=E6=97=B6=E9=97=B4=E7=BB=B4=E6=8C=87?= =?UTF-8?q?=E6=A0=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/flask_app.py | 16 +++++++++++++++- static/app.js | 31 ++++++++++++++++++++----------- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/backend/flask_app.py b/backend/flask_app.py index 9b8d96f..e39ccee 100644 --- a/backend/flask_app.py +++ b/backend/flask_app.py @@ -352,8 +352,19 @@ def bootstrap(): cost_q2 = sum_finance(months_q2, "cost_expense") revenue_month = sum_finance([current_month], "revenue") cost_month = sum_finance([current_month], "cost_expense") - # Contract aggregates + # Contract aggregates — time-based signed_amount = sum(x["expected_contract_amount"] or 0 for x in operations if x["project_status"] == "已签约") + from datetime import date + today = date.today() + def contract_in_period(op, start, end): + if op["project_status"] != "已签约": return False + try: + d = date.fromisoformat(op["created_at"][:10]) + return start <= d <= end + except: return False + signed_annual = sum(x["expected_contract_amount"] or 0 for x in operations if contract_in_period(x, date(2026,1,1), date(2026,12,31))) + signed_q2 = sum(x["expected_contract_amount"] or 0 for x in operations if contract_in_period(x, date(2026,4,1), date(2026,6,30))) + signed_month = sum(x["expected_contract_amount"] or 0 for x in operations if contract_in_period(x, date(2026,6,1), date(2026,6,30))) pipeline_amount = sum(x["expected_contract_amount"] or 0 for x in operations if x["project_status"] not in ["已签约","已丢单","已归档","已完成"]) signed_not_executed = sum(x["expected_contract_amount"] or 0 for x in operations if x["project_type"] == "execution" and x["execution_progress"] < 100) summary = { @@ -368,6 +379,9 @@ def bootstrap(): "upcoming_products": len([x for x in products if x["status"] in ["规划中", "设计中", "开发中", "测试中"]]), # Extended finance metrics "signed_amount": signed_amount, + "signed_annual": signed_annual, + "signed_q2": signed_q2, + "signed_month": signed_month, "pipeline_amount": pipeline_amount, "revenue_annual": revenue_annual, "revenue_q2": revenue_q2, diff --git a/static/app.js b/static/app.js index 0a7bacf..d7b94ac 100644 --- a/static/app.js +++ b/static/app.js @@ -93,7 +93,25 @@ function render() { function renderHome() { const { summary, financeMonthly } = state.data; - const m = summary.metrics; + const rows1 = [ + ["年度累计签约", money(m.signed_annual || m.signed_amount)], + ["Q2 累计签约", money(m.signed_q2 || 0)], + ["本月新增签约", money(m.signed_month || 0)], + ["合同流程中", money(m.pipeline_amount)], + ]; + const rows2 = [ + ["年度累计确收", money(m.revenue_annual)], + ["Q2 累计确收", money(m.revenue_q2)], + ["本月新增确收", money(m.monthly_revenue)], + ["已签约未执行", money(m.signed_not_executed)], + ]; + const rows3 = [ + ["年度累计毛利", money(m.gross_annual)], + ["Q2 累计毛利", money(m.gross_q2)], + ["本月新增毛利", money(m.monthly_net_profit)], + ["合同毛利率", m.revenue_annual ? Math.round(m.gross_annual / m.revenue_annual * 100) + "%" : "—"], + ]; + const tblCard = (title, rows) => card(`

${title}

${rows.map(([label, value]) => ``).join("")}
${label}${value}
`, "p-4"); document.querySelector("#home").innerHTML = `
@@ -108,16 +126,7 @@ function renderHome() { ["已签约未执行", money(m.signed_not_executed), "finance"], ].map(([label, value, tab]) => ``).join("")}
-
- ${[ - ["已签约合同总额", money(m.signed_amount), "projects"], - ["合同流程中", money(m.pipeline_amount), "projects"], - ["年度累计确收", money(m.revenue_annual), "finance"], - ["Q2 累计确收", money(m.revenue_q2), "finance"], - ["年度累计毛利", money(m.gross_annual), "finance"], - ["Q2 累计毛利", money(m.gross_q2), "finance"], - ].map(([label, value, tab]) => ``).join("")} -
+
${tblCard("合同金额", rows1)}${tblCard("确收金额", rows2)}${tblCard("确收毛利", rows3)}
${card(`

财务趋势

${badge("YYYY-MM")}
`, "p-4")} ${card(`

风险提醒

${(summary.risks.length ? summary.risks : [{ title: "暂无高风险", content: "当前无明确阻塞,按周更新即可。" }]).map((r) => `

${r.title}

${r.content}

`).join("")}
`, "p-5")}