// overview_plan.js — 预算总览模块(5 个工作台数据聚合)
function renderOverviewPlan() {
const view = state.overviewView || "monthly";
const api = view === "quarterly" ? "/api/overview/plan-quarterly" : "/api/overview/plan-monthly";
const container = document.querySelector("#overview_plan");
if (!container) return;
container.innerHTML = '
加载中...
';
fetch(api).then(r => r.json()).then(data => {
renderOverviewPlanData(data, view);
}).catch(() => {
container.innerHTML = '加载失败
';
});
}
function renderOverviewPlanData(data, view) {
const container = document.querySelector("#overview_plan");
if (!container) return;
const moneyIntL = (v) => Math.round(Number(v || 0)).toLocaleString("zh-CN");
const card = (body, cls) => '' + body + '
';
const isQuarterly = view === "quarterly";
const headers = isQuarterly ? ['Q1','Q2','Q3','Q4'] : ['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月'];
const cols = isQuarterly ? 4 : 12;
const d = data.dept;
const cf = data.dept_cf;
const p = data.project;
// ====== 部门损益情况 ======
var deptThead = '| 指标 | 年度累计 | ';
for (var hi = 0; hi < cols; hi++) { deptThead += '' + headers[hi] + ' | '; }
deptThead += '
';
var deptRows = [
{ label: '项目毛利', vals: d.project_gross, annual: d.annual[0] },
{ label: '部门费用', vals: d.dept_expense, annual: d.annual[1] },
{ label: '利润', vals: d.profit, annual: d.annual[2] }
];
var deptTbody = '';
for (var dri = 0; dri < 3; dri++) {
var dr = deptRows[dri];
var rowCls = dri === 2 ? 'font-semibold' : '';
var rowHtml = '| ' + dr.label + ' | ';
var annualCls = dri === 2 ? (dr.annual >= 0 ? 'text-green-600' : 'text-red-600') : 'text-slate-700';
rowHtml += '' + moneyIntL(dr.annual) + ' | ';
for (var i = 0; i < cols; i++) {
var cellCls = dri === 2 ? (dr.vals[i] >= 0 ? 'text-green-600' : 'text-red-600') : 'text-slate-700';
rowHtml += '' + moneyIntL(dr.vals[i]) + ' | ';
}
deptTbody += rowHtml + '
';
}
var deptCard = card('部门损益情况 部门利润 = 所有项目产生的毛利 - 部门 1 级产生的人力成本,研发成本,差旅和其他支出
' + deptThead + '' + deptTbody + '
', 'p-4');
// ====== 部门现金流 ======
var cfRows = [
{ label: '项目现金流', vals: cf.project_cf, annual: cf.annual[0] },
{ label: '部门现金流', vals: cf.dept_cf_item, annual: cf.annual[1] },
{ label: '经营现金流', vals: cf.bl_cf, annual: cf.annual[2] }
];
var cfTbody = '';
for (var cfri = 0; cfri < 3; cfri++) {
var cfr = cfRows[cfri];
var cfRowCls = cfri === 2 ? 'font-semibold' : '';
var rowHtml = '| ' + cfr.label + ' | ';
var cAnnualCls = cfri === 2 ? (cfr.annual >= 0 ? 'text-green-600' : 'text-red-600') : 'text-slate-700';
rowHtml += '' + moneyIntL(cfr.annual) + ' | ';
for (var i = 0; i < cols; i++) {
var cCellCls = cfri === 2 ? (cfr.vals[i] >= 0 ? 'text-green-600' : 'text-red-600') : 'text-slate-700';
rowHtml += '' + moneyIntL(cfr.vals[i]) + ' | ';
}
cfTbody += rowHtml + '
';
}
var cfCard = card('部门现金流 部门现金流=所有项目产生的现金流 - 部门一级因费用产生的现金流出或流入
' + deptThead + '' + cfTbody + '
', 'p-4');
// ====== 项目经营详情 ======
var LABELS = ['合同金额','确收金额','确收毛利','成本','支出','回款','项目现金流'];
var projVals = [p.revenue, p.gross, p.cost, p.paid, p.payment, p.cashflow];
var projAnnual = p.annual; // [sign, revenue_sum, gross_sum, cost_sum, paid_sum, payment_sum, cf_sum]
var projThead = '| 指标 | 年度累计 | ';
for (var phi = 0; phi < cols; phi++) { projThead += '' + headers[phi] + ' | '; }
projThead += '
';
var projTbody = '';
for (var ri = 0; ri < 7; ri++) {
var rowHtml = '| ' + LABELS[ri] + ' | ';
rowHtml += '' + (ri === 0 ? moneyIntL(p.sign) : moneyIntL(projAnnual[ri])) + ' | ';
for (var i = 0; i < cols; i++) {
var val = ri === 0 ? 0 : (projVals[ri - 1] ? projVals[ri - 1][i] : 0);
var cls = 'text-slate-700';
if (ri === 2) cls = 'text-green-600';
if (ri === 6) cls = val >= 0 ? 'text-green-600' : 'text-red-600';
rowHtml += '' + moneyIntL(val) + ' | ';
}
projTbody += rowHtml + '
';
}
var projCard = card('项目经营详情 所有项目产生的签单,确收,毛利,回款,当期成本,当期流出,现金流
' + projThead + '' + projTbody + '
', 'p-4');
// 视图切换按钮
var viewBtns = '';
container.innerHTML = '' + viewBtns + deptCard + cfCard + projCard + '
';
if (window.lucide) window.lucide.createIcons();
}
window.setOverviewView = (v) => {
state.overviewView = v;
renderOverviewPlan();
};