diff --git a/static/modules/finance.js b/static/modules/finance.js
index 64f6de3..746ad27 100644
--- a/static/modules/finance.js
+++ b/static/modules/finance.js
@@ -113,7 +113,7 @@ function renderFinance() {
const finHeaderBase = `
${planFilterTabs}
@@ -254,11 +254,9 @@ function renderPlan() {
{ label: '已确收', hideUnsigned: true, value: ctx => moneyWan(ctx.sumRev), color: 'text-blue-700' },
{ label: '毛利', value: ctx => money(ctx.sumGross), color: 'text-green-700' },
{ label: '成本', value: ctx => moneyWan(ctx.sumCost), color: 'text-rose-700' },
- { label: '项目利润', value: ctx => { const v = ctx.sumGross; return { val: moneyWan(v), cls: v >= 0 ? 'text-green-600' : 'text-red-600' }; }, color: null },
{ label: '已回款', hideUnsigned: true, value: ctx => moneyWan(ctx.sumPay), color: 'text-amber-700' },
{ label: '已付', hideUnsigned: true, value: ctx => moneyWan(ctx.sumPaid), color: 'text-purple-700' },
{ label: '现金流', hideUnsigned: true, value: ctx => { const v = ctx.sumPay - ctx.sumPaid; return { val: money(v), cls: v >= 0 ? 'text-green-600' : 'text-red-600' }; }, color: null },
- { label: '执行率', hideUnsigned: true, value: ctx => ctx.sumRev && ctx.signTotal ? Math.round(ctx.sumRev / ctx.signTotal * 100) + '%' : '—', color: 'text-slate-500' },
{ label: '毛利率', hideUnsigned: true, value: ctx => ctx.sumRev && ctx.sumGross ? Math.round(ctx.sumGross / ctx.sumRev * 100) + '%' : '—', color: 'text-slate-500' },
{ label: '回款率', hideUnsigned: true, value: ctx => ctx.sumRev && ctx.sumPay ? Math.round(ctx.sumPay / ctx.sumRev * 100) + '%' : '—', color: 'text-slate-500' },
{ label: '付款率', hideUnsigned: true, value: ctx => ctx.sumCost && ctx.sumPaid ? Math.round(ctx.sumPaid / ctx.sumCost * 100) + '%' : '—', color: 'text-slate-500' },
@@ -298,11 +296,11 @@ function renderPlan() {
{ key: 'gross', label: '毛利' },
{ key: 'gross_rate', label: '毛利率' },
{ key: 'payment', label: '回款' },
- { key: 'cashflow', label: '现金流' },
{ key: 'pay_rate', label: '回款率' },
{ key: 'cost', label: '成本' },
{ key: 'paid', label: '付款' },
{ key: 'paid_rate', label: '付款率' },
+ { key: 'cashflow', label: '现金流' },
];
const UNSIGNED_COLS = [
{ key: 'client_name', label: '客户' },
@@ -344,7 +342,7 @@ function renderPlan() {
const grossR = rev && gross ? Math.round(gross / rev * 100) + '%' : '
—';
const cf = cashflow ? money(cashflow) : '
—';
const cfCls = cashflow >= 0 ? 'text-green-600' : 'text-red-600';
- return `
| ${esc(pf.client_name || "")} | ${esc(pf.customer_name)} | ${planInlineSelect('weight', pf.id, 'weight', pf.weight || '20%', ['20%','40%','60%','80%','100%'])} | ${planInlineSelect('ptype', pf.id, 'project_type', pf.project_type || '待签约', ['待签约','已签约'])} | ${money(pf.sign_amount)} | ${fmtNoUnit(rev)} | ${fmtNoUnit(gross)} | ${grossR} | ${fmtNoUnit(payment)} | ${cf} | ${payR} | ${fmtNoUnit(cost)} | ${fmtNoUnit(paid)} | ${paidR} |
`;
+ return `
| ${esc(pf.client_name || "")} | ${esc(pf.customer_name)} | ${planInlineSelect('weight', pf.id, 'weight', pf.weight || '20%', ['20%','40%','60%','80%','100%'])} | ${planInlineSelect('ptype', pf.id, 'project_type', pf.project_type || '待签约', ['待签约','已签约'])} | ${money(pf.sign_amount)} | ${fmtNoUnit(rev)} | ${fmtNoUnit(gross)} | ${grossR} | ${fmtNoUnit(payment)} | ${payR} | ${fmtNoUnit(cost)} | ${fmtNoUnit(paid)} | ${paidR} | ${cf} |
`;
};
// 待签约简版行
const tdRowUnsigned = (pf, cost, gross) => {
@@ -1010,7 +1008,7 @@ function renderPlanOverview() {
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 = ['合同金额','确收金额','确收毛利','成本','已付','回款','项目现金流'];
+ const LABELS = ['合同金额','确收金额','确收毛利','成本','支出','回款','项目现金流'];
// 每行的年度累计 + 12个月值
const annualVals = [
annualSums.sign, annualSums.revenue, annualSums.gross, annualSums.cost, annualSums.paid,
@@ -1032,6 +1030,7 @@ function renderPlanOverview() {
else { var fk = fmFields[ri]; if (fk) val = fm[mi][fk] || 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) + ' | ';
}
@@ -1060,11 +1059,12 @@ function renderPlanOverview() {
for (var dri = 0; dri < 3; dri++) {
var dr = deptRows[dri];
var rowCls = dri === 2 ? 'font-semibold' : '';
- var valCls = dri === 2 ? 'text-green-600' : 'text-slate-700';
var rowHtml = '
| ' + dr.label + ' | ';
- rowHtml += '' + moneyIntL(dr.annual) + ' | ';
+ var annualCls = dri === 2 ? (dr.annual >= 0 ? 'text-green-600' : 'text-red-600') : 'text-slate-700';
+ rowHtml += '' + moneyIntL(dr.annual) + ' | ';
for (var dmi = 0; dmi < 12; dmi++) {
- rowHtml += '' + moneyIntL(dr.vals[dmi]) + ' | ';
+ var cellCls = dri === 2 ? (dr.vals[dmi] >= 0 ? 'text-green-600' : 'text-red-600') : 'text-slate-700';
+ rowHtml += '' + moneyIntL(dr.vals[dmi]) + ' | ';
}
deptTbody += rowHtml + '
';
}
@@ -1128,7 +1128,7 @@ function renderPlanQuarterlyOverview() {
const fm = computePlanMonthly(planFinances);
const moneyIntL = (v) => Math.round(Number(v || 0)).toLocaleString("zh-CN");
const card = (body, cls) => '
' + body + '
';
- const LABELS = ['合同金额','确收金额','确收毛利','成本','已付'];
+ const LABELS = ['合同金额','确收金额','确收毛利','成本','支出'];
const qLbl = ['Q1','Q2','Q3','Q4'];
const qRanges = [[0,1,2],[3,4,5],[6,7,8],[9,10,11]];
var annualSums2 = { sign: 0, revenue: 0, gross: 0, cost: 0, payment: 0, paid: 0 };
diff --git a/templates/index.html b/templates/index.html
index 1cbbd3f..ab50489 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -80,7 +80,7 @@
-
OPC Manager v1.0.0.33
+
OPC Manager v1.0.0.34