From 8952829fe5cd4eebd4748ed9c1d277de2a322333 Mon Sep 17 00:00:00 2001 From: mac Date: Wed, 8 Jul 2026 16:05:45 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E8=AE=A1=E5=88=92=E6=80=BB=E8=A7=88?= =?UTF-8?q?=E7=8B=AC=E7=AB=8B=E6=95=B0=E6=8D=AE=E6=BA=90+=E5=AE=9E?= =?UTF-8?q?=E9=99=85=E6=A8=A1=E5=9D=97=E8=A1=A8=E5=A4=B4=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 计划月度/季度总览: 改用planFinances计算,不再引用实际模块数据 - 新增computePlanMonthly函数从planFinances计算月度数据 - 实际模块SIGNED_COLS/UNSIGNED_COLS补全client_name列 - theadCols计数修正(14/7) - 版本号 v1.0.0.28 --- static/modules/finance.js | 6 ++-- static/modules/plan.js | 68 +++++++++++++++++++++++++++------------ templates/index.html | 2 +- 3 files changed, 52 insertions(+), 24 deletions(-) diff --git a/static/modules/finance.js b/static/modules/finance.js index 51b4224..f056205 100644 --- a/static/modules/finance.js +++ b/static/modules/finance.js @@ -286,14 +286,14 @@ function renderFinance() { return h; }; const SIGNED_COLS = [ - { key: 'customer_name', label: '项目名称' }, { key: 'sign_amount', label: '签约金额' }, + { key: 'client_name', label: '客户' }, { key: 'customer_name', label: '项目名称' }, { key: 'sign_amount', label: '签约金额' }, { key: 'rev', label: '已确收' }, { key: 'gross', label: '毛利' }, { key: 'cost', label: '成本' }, { key: 'profit', label: '项目利润' }, { key: 'payment', label: '已回款' }, { key: 'paid', label: '已付' }, { key: 'cashflow', label: '现金流' }, { key: 'exe_rate', label: '执行率' }, { key: 'gross_rate', label: '毛利率' }, { key: 'pay_rate', label: '回款率' }, { key: 'paid_rate', label: '付款率' }, ]; const UNSIGNED_COLS = [ - { key: 'customer_name', label: '项目名称' }, { key: 'sign_amount', label: '签约金额' }, + { key: 'client_name', label: '客户' }, { key: 'customer_name', label: '项目名称' }, { key: 'sign_amount', label: '签约金额' }, { key: 'sign_month', label: '签约月份' }, { key: 'gross', label: '毛利' }, { key: 'cost', label: '成本' }, { key: 'profit', label: '项目利润' }, ]; @@ -305,7 +305,7 @@ function renderFinance() { return typeof v === 'object' ? [c.label, v.val, v.cls] : [c.label, v, c.color]; }); const thead = isUnsigned ? buildThead(UNSIGNED_COLS, 'uns') : buildThead(SIGNED_COLS, 'sig'); - const theadCols = isUnsigned ? 6 : 13; + const theadCols = isUnsigned ? 7 : 14; const tbody = rows.length ? `${rows.join("")}` : `${emptyText}`; const cardGrid = isUnsigned ? 'grid-cols-4' : 'grid-cols-6'; diff --git a/static/modules/plan.js b/static/modules/plan.js index ec64d5c..999c639 100644 --- a/static/modules/plan.js +++ b/static/modules/plan.js @@ -965,11 +965,35 @@ window.deletePlanItem = async () => { } } + +// 从 planFinances 计算月度数据 +function computePlanMonthly(planFinances) { + var pfs = planFinances || []; + var months = []; + var year = new Date().getFullYear(); + for (var mi = 1; mi <= 12; mi++) { months.push(year + '-' + String(mi).padStart(2, '0')); } + var data = []; + for (var i = 0; i < 12; i++) { + var month = months[i]; + var sign = 0, revenue = 0, gross = 0, payment = 0, cost = 0, paid = 0; + for (var j = 0; j < pfs.length; j++) { + var pf = pfs[j]; + if ((pf.sign_month || '') === month) sign += parseFloat(pf.sign_amount || 0); + var bd = []; try { bd = JSON.parse(pf.budget_data || '[]'); } catch(e) {} + var b = bd.find(function(x) { return (x.month || '') === month; }); + if (b) { revenue += parseFloat(b.rev || 0); gross += parseFloat(b.gross || 0); payment += parseFloat(b.payment || 0); } + var ed = []; try { ed = JSON.parse(pf.expense_data || '[]'); } catch(e) {} + var e = ed.find(function(x) { return (x.month || '') === month; }); + if (e) { cost += parseFloat(e.cost || 0); paid += parseFloat(e.paid || 0); } + } + data.push({ month: month, sign: Math.round(sign), revenue: Math.round(revenue), gross: Math.round(gross), payment: Math.round(payment), cost: Math.round(cost), paid: Math.round(paid) }); + } + return data; +} // 总览渲染 function renderPlanOverview() { - const { summary, financeMonthly } = state.data; - if (!summary) return; - const m = summary.metrics; + const planFinances = state.data.planFinances || []; + const fm = computePlanMonthly(planFinances); const moneyIntL = (v) => Math.round(Number(v || 0)).toLocaleString("zh-CN"); const moneyWan = (v) => { const n = Number(v || 0); @@ -977,20 +1001,20 @@ function renderPlanOverview() { }; const card = (body, cls) => '
' + body + '
'; - // 月度数据 (financeMonthly 有12个月) - const fm = financeMonthly || []; + // 从 planFinances 计算年度累计 + var annualSums = { sign: 0, revenue: 0, gross: 0, cost: 0, payment: 0, paid: 0 }; + for (var i = 0; i < fm.length; i++) { + annualSums.sign += fm[i].sign; annualSums.revenue += fm[i].revenue; + annualSums.gross += fm[i].gross; annualSums.cost += fm[i].cost; + annualSums.payment += fm[i].payment; annualSums.paid += fm[i].paid; + } const mLbl = ['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月']; const LABELS = ['合同金额','确收金额','确收毛利','成本','项目利润','回款金额','已付','现金流']; // 每行的年度累计 + 12个月值 const annualVals = [ - m.signed_annual || m.signed_amount || 0, - m.revenue_annual || 0, - m.gross_annual || 0, - m.cost_annual || 0, - m.profit_annual || 0, - m.payment_annual || 0, - m.paid_annual || 0, - m.cashflow_annual || 0, + annualSums.sign, annualSums.revenue, annualSums.gross, annualSums.cost, + annualSums.gross - annualSums.cost, annualSums.payment, annualSums.paid, + annualSums.payment - annualSums.paid, ]; // 字段映射: sign, revenue, gross, cost, profit(=gross-cost), payment, paid, cashflow(=payment-paid) const fmFields = ['sign','revenue','gross','cost',null,'payment','paid',null]; @@ -1027,23 +1051,27 @@ function renderPlanOverview() { if (window.lucide) window.lucide.createIcons(); // 渲染图表(复用 home.js 的 moneyTick / chartOptions / monthLabels) - if (financeMonthly && window.Chart) { - renderPlanCharts(financeMonthly); + if (fm && window.Chart) { + renderPlanCharts(fm); } } function renderPlanQuarterlyOverview() { - const { summary, financeMonthly } = state.data; - if (!summary) return; - const m = summary.metrics; + const planFinances = state.data.planFinances || []; + const fm = computePlanMonthly(planFinances); const moneyIntL = (v) => Math.round(Number(v || 0)).toLocaleString("zh-CN"); const card = (body, cls) => '
' + body + '
'; - const fm = financeMonthly || []; const LABELS = ['合同金额','确收金额','确收毛利','成本','项目利润','回款金额','已付','现金流']; const qLbl = ['Q1','Q2','Q3','Q4']; const qRanges = [[0,1,2],[3,4,5],[6,7,8],[9,10,11]]; - const annualVals = [m.signed_annual||m.signed_amount||0, m.revenue_annual||0, m.gross_annual||0, m.cost_annual||0, m.profit_annual||0, m.payment_annual||0, m.paid_annual||0, m.cashflow_annual||0]; + var annualSums2 = { sign: 0, revenue: 0, gross: 0, cost: 0, payment: 0, paid: 0 }; + for (var i2 = 0; i2 < fm.length; i2++) { + annualSums2.sign += fm[i2].sign; annualSums2.revenue += fm[i2].revenue; + annualSums2.gross += fm[i2].gross; annualSums2.cost += fm[i2].cost; + annualSums2.payment += fm[i2].payment; annualSums2.paid += fm[i2].paid; + } + const annualVals = [annualSums2.sign, annualSums2.revenue, annualSums2.gross, annualSums2.cost, annualSums2.gross - annualSums2.cost, annualSums2.payment, annualSums2.paid, annualSums2.payment - annualSums2.paid]; const fmFields = ['sign','revenue','gross','cost',null,'payment','paid',null]; // Calculate quarterly sums diff --git a/templates/index.html b/templates/index.html index 81029ec..121c3ad 100644 --- a/templates/index.html +++ b/templates/index.html @@ -80,7 +80,7 @@
-

OPC Manager v1.0.0.27

+

OPC Manager v1.0.0.28

科普 OPC 工作台