// home.js — 首页渲染 + 财务趋势图 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)], ]; const rows2 = [ ["年度累计确收", money(m.revenue_annual)], ["Q2 累计确收", money(m.revenue_q2)], ["本月新增确收", money(m.monthly_revenue)], ]; const rows3 = [ ["年度累计毛利", money(m.gross_annual)], ["Q2 累计毛利", money(m.gross_q2)], ["本月新增毛利", money(m.monthly_net_profit)], ]; const tblCard = (title, rows) => card(`

${title}

${rows.map(([label, value]) => ``).join("")}
${label}${value}
`, "p-4"); document.querySelector("#home").innerHTML = `
${[ ["经营管理", m.total_projects, "finance"], ["重点工作与台账", m.total_proposals, "projects"], ["业务方案", m.total_products, "proposals"], ["产品迭代", m.upcoming_products, "products"], ].map(([label, value, tab]) => ``).join("")}
${tblCard("合同金额", rows1)}${tblCard("确收金额", rows2)}${tblCard("确收毛利", rows3)}
${card(`

月度签约趋势

2026
`, "p-4")} ${card(`

月度确收与毛利

2026
`, "p-4")} ${card(`

月度回款与费用

2026
`, "p-4")}
${card(`

近期动态

${summary.recent.map((r) => `
${r.content}
${r.followed_at}
`).join("")}
`, "p-5")}
`; renderCharts(financeMonthly); } function chartOptions(yCallback) { return { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: "bottom", labels: { boxWidth: 12, font: { size: 11 } } } }, scales: { x: { ticks: { font: { size: 10 } }, grid: { display: false } }, y: { ticks: { font: { size: 11 }, callback: yCallback } }, }, }; } const moneyTick = (v) => v >= 10000 ? (v / 10000).toFixed(0) + "万" : v; const monthLabels = (data) => data.map((x) => parseInt(x.month.split("-")[1]) + "月"); function renderCharts(data) { const labels = monthLabels(data); const baseOpts = chartOptions(moneyTick); // 图1:月度签约 const c1 = document.querySelector("#chartSign"); if (c1 && window.Chart) { if (state.chart) state.chart.destroy(); state.chart = new Chart(c1, { type: "line", data: { labels, datasets: [ { label: "签约金额", data: data.map((x) => x.sign || 0), borderColor: "#6366f1", backgroundColor: "rgba(99,102,241,0.06)", fill: true, tension: 0.3 }, ]}, options: baseOpts, }); } // 图2:月度确收与毛利 const c2 = document.querySelector("#chartRev"); if (c2 && window.Chart) { if (state.chart2) state.chart2.destroy(); state.chart2 = new Chart(c2, { type: "line", data: { labels, datasets: [ { label: "确收", data: data.map((x) => x.revenue || 0), borderColor: "#2563eb", backgroundColor: "rgba(37,99,235,0.06)", fill: true, tension: 0.3 }, { label: "毛利", data: data.map((x) => x.net_profit || 0), borderColor: "#059669", backgroundColor: "rgba(5,150,105,0.06)", fill: true, tension: 0.3 }, ]}, options: baseOpts, }); } // 图3:月度回款与费用 const c3 = document.querySelector("#chartCash"); if (c3 && window.Chart) { if (state.chart3) state.chart3.destroy(); state.chart3 = new Chart(c3, { type: "bar", data: { labels, datasets: [ { label: "回款", data: data.map((x) => x.payment || 0), backgroundColor: "#d97706", borderRadius: 4 }, { label: "费用", data: data.map((x) => x.cost || 0), backgroundColor: "#ef4444", borderRadius: 4 }, ]}, options: baseOpts, }); } }