@@ -7,11 +7,14 @@ function renderHome() {
// 回款提醒
const yrRev = m . revenue _annual || 0 , yrPay = m . payment _annual || 0 , yrUnpaid = yrRev - yrPay ;
const yrPayRate = yrRev > 0 ? Math . round ( yrPay / yrRev * 100 ) : 0 ;
const yrUnpaidWan = Math . round ( yrUnpaid / 10000 ) ;
const yrUnpaidWan = Math . round ( Math . abs ( yrUnpaid ) / 10000 ) ;
const payRateCls = yrPayRate < 30 ? 'text-red-600' : yrPayRate < 80 ? 'text-amber-600' : 'text-green-600' ;
const unpaidLabel = yrUnpaid >= 0
? '你还有 <strong class=\"text-red-600\">' + yrUnpaidWan + '万</strong> 未回款'
: '超额回款 <strong class=\"text-green-600\">' + yrUnpaidWan + '万</strong>' ;
const payReminder = yrRev > 0 ? '<div class=\"flex items-center gap-3 px-4 py-3 rounded-lg border\" style=\"background:linear-gradient(135deg,#fef3c7,#fde68a);border-color:#f59e0b\">' +
'<i data-lucide=\"bell-ring\" class=\"text-amber-600 flex-shrink-0\" style=\"width:18px;height:18px\"></i>' +
'<span class=\"text-sm text-amber-900\"><strong>回款提醒:</strong>本年度确收 <strong>' + moneyInt ( yrRev ) + '</strong>,回款 <strong>' + moneyInt ( yrPay ) + '</strong>, 你还有 <strong class=\"text-red-600\"> ' + yrU npaidWan + '万</strong> 未回款 ,当前回款率:<strong class=\"' + payRateCls + '\">' + yrPayRate + '%</strong></span>' +
'<span class=\"text-sm text-amber-900\"><strong>回款提醒:</strong>本年度确收 <strong>' + moneyInt ( yrRev ) + '</strong>,回款 <strong>' + moneyInt ( yrPay ) + '</strong>, ' + u npaidLabel + ',当前回款率:<strong class=\"' + payRateCls + '\">' + yrPayRate + '%</strong></span>' +
'</div>' : '' ;
const rows1 = [
[ "年度累计" , moneyInt ( m . signed _annual || m . signed _amount ) ] ,
@@ -123,8 +126,7 @@ function renderHome() {
] . map ( ( [ label , value , tab ] ) => ` <button class="metric-card" onclick="switchTab(' ${ tab } ')"><span class="flex items-center gap-2 text-xs text-slate-500"><i data-lucide="gauge"></i> ${ label } </span><strong class="mt-2 block text-2xl"> ${ value } </strong></button> ` ) . join ( "" ) }
</div> ` }
${ payReminder }
${ card ( ` <h3 class="text-sm font-bold text-slate-700 mb-3">部门经营情况</h3><div class="overflow-x-auto"><table class="w-full text-sm"><thead><tr class="border-b border-slate-200"><th class="py-2 text-left text-slate-500">指标</th><th class="py-2 text-right font-semibold text-slate-700">年度累计</th><th class="py-2 text-right font-semibold text-slate-700">上季度累计</th><th class="py-2 text-right font-semibold text-slate-700">上月累计</th><th class="py-2 text-right font-semibold text-slate-700">本季度累计</th><th class="py-2 text-right font-semibold text-slate-400">季环比</th><th class="py-2 text-right font-semibold text-slate-700">本月累计</th><th class="py-2 text-right font-semibold text-slate-400">月环比</th></tr></thead><tbody>
${ ( ( ) => {
${ ( ( ) => {
var d = [
[ '项目毛利' , [ m . profit _annual || 0 , m . profit _q2 || 0 , m . profit _month || 0 , m . profit _prev _q || 0 , m . profit _prev _month || 0 ] ,
[ m . profit _q2 || 0 , m . profit _prev _q || 0 ] , [ m . profit _month || 0 , m . profit _prev _month || 0 ] ] ,
@@ -140,27 +142,32 @@ function renderHome() {
] ] ,
[ '项目现金流' , [ m . cashflow _annual || 0 , m . cashflow _q2 || 0 , m . cashflow _month || 0 , m . cashflow _prev _q || 0 , m . cashflow _prev _month || 0 ] ,
[ m . cashflow _q2 || 0 , m . cashflow _prev _q || 0 ] , [ m . cashflow _month || 0 , m . cashflow _prev _month || 0 ] ] ,
[ '部门费用现金 流' , [ m . expense _paid _annual || 0 , m . expense _paid _q2 || 0 , m . expense _paid _month || 0 , m . expense _paid _prev _q || 0 , m . expense _paid _prev _month || 0 ] ,
[ '部门费用流出 ' , [ m . expense _paid _annual || 0 , m . expense _paid _q2 || 0 , m . expense _paid _month || 0 , m . expense _paid _prev _q || 0 , m . expense _paid _prev _month || 0 ] ,
[ m . expense _paid _q2 || 0 , m . expense _paid _prev _q || 0 ] , [ m . expense _paid _month || 0 , m . expense _paid _prev _month || 0 ] ] ,
[ '部门现金流' , [ m . dept _cf _annual || 0 , m . dept _cf _q2 || 0 , m . dept _cf _month || 0 , m . dept _cf _prev _q || 0 , m . dept _cf _prev _month || 0 ] ,
[ m . dept _cf _q2 || 0 , m . dept _cf _prev _q || 0 ] , [ m . dept _cf _month || 0 , m . dept _cf _prev _month || 0 ] ]
] ;
var h = '' ;
var netCls = function ( di , raw ) { if ( di === 2 || di === 5 ) return raw > = 0 ? 'text-green-600' : 'text-red-600' ; if ( di === 3 ) return raw >= 0 ? 'text-green-600' : 'text-red-600' ; return 'text-slate-800' ; } ;
for (var di = 0; di < 6; di++) {
var r = d[di];
h += '<tr class="border-b border-slate-100 last:border-0"><td class="py-2 text-left font-semibold text-slate-700">' + r[0] + '</td>' +
'<td class="py-2 text-right font-semibold ' + netCls(di, r[1][0]) + '">' + moneyInt(r[1][0]) + '</td>' +
'<td class="py-2 text-right font-semibold ' + netCls(di, r[1][3]) + '">' + moneyInt(r[1][3]) + '</td>' +
'<td class="py-2 text-right font-semibold ' + netCls(di, r[1][4]) + '">' + moneyInt(r[1][4]) + '</td>' +
' <td class="py-2 text-righ t font-semibold ' + netCls(di, r[1][1]) + '">' + moneyInt(r[1][1]) + '</td>' +
'<td class="py-2 text-right">' + qoq(r[2][0], r[2][1]) + '</td>' +
'<td class="py-2 text-right font-semibold ' + netCls(di, r[1][2]) + '">' + moneyInt(r[1][2]) + '</td>' +
'<td class="py-2 text-right">' + qoq(r[3][0], r[3][1]) + '</td></tr>';
}
return h;
var buildDeptTable = function ( title , dataRows ) {
var h = '' ;
for ( var di = 0 ; di < dataRows . length ; di ++ ) {
var r = dataRows [ di ] ;
var rawNet = r [ 1 ] [ 0 ] ;
var isNet = r [ 0 ] === '部门净利' || r [ 0 ] === '部门现金流' ;
var isCF = r [ 0 ] === '项目现金流' ;
var cls = isNet ? ( rawNet >= 0 ? 'text-green-600' : 'text-red-600' ) : isCF ? ( rawNet >= 0 ? 'text-green-600' : 'text-red-600' ) : 'text-slate-800' ;
h += '<tr class="border-b border-slate-100 last:border-0"> <td class="py-2 text-lef t font-semibold text-slate-700">' + r [ 0 ] + '</td>' +
'<td class="py-2 text-right font-semibold ' + cls + '">' + moneyInt ( r [ 1 ] [ 0 ] ) + '</td>' +
'<td class="py-2 text-right font-semibold ' + cls + '">' + moneyInt ( r [ 1 ] [ 3 ] ) + '</td>' +
'<td class="py-2 text-right font-semibold ' + cls + '">' + moneyInt ( r [ 1 ] [ 4 ] ) + '</td>' +
'<td class="py-2 text-right font-semibold ' + cls + '">' + moneyInt ( r [ 1 ] [ 1 ] ) + '</td>' +
'<td class="py-2 text-right">' + qoq ( r [ 2 ] [ 0 ] , r [ 2 ] [ 1 ] ) + '</td>' +
'<td class="py-2 text-right font-semibold ' + cls + '">' + moneyInt ( r [ 1 ] [ 2 ] ) + '</td>' +
'<td class="py-2 text-right">' + qoq ( r [ 3 ] [ 0 ] , r [ 3 ] [ 1 ] ) + '</td></tr>' ;
}
return card('<h3 class="text-sm font-bold text-slate-700 mb-3">' + title + '</h3><div class="overflow-x-auto"><table class="w-full text-sm"><thead><tr class="border-b border-slate-200"><th class="py-2 text-left text-slate-500">指标</th><th class="py-2 text-right font-semibold text-slate-700">年度累计</th><th class="py-2 text-right font-semibold text-slate-700">上季度累计</th><th class="py-2 text-right font-semibold text-slate-700">上月累计</th><th class="py-2 text-right font-semibold text-slate-700">本季度累计</th><th class="py-2 text-right font-semibold text-slate-400">季环比</th><th class="py-2 text-right font-semibold text-slate-700">本月累计</th><th class="py-2 text-right font-semibold text-slate-400">月环比</th></tr></thead><tbody>' + h + '</tbody></table></div>', 'p-4');
};
return buildDeptTable('部门经营情况', d.slice(0, 3)) + buildDeptTable('部门现金流', d.slice(3, 6));
})()}
</tbody></table></div> ` , "p-4" ) }
${ card ( ` <h3 class="text-sm font-bold text-slate-700">业务(项目)财务概览</h3><p class="text-xs text-slate-400 mb-3">合同 → 确收 → 毛利 → 成本 → 项目利润 → 回款 → 已付 → 现金流</p><div class="overflow-x-auto"><table class="w-full text-sm"><thead> ${ thead } </thead><tbody> ${ tbody } </tbody></table></div> ` , "p-4" ) }
<div class="grid grid-cols-4 gap-5">
${ card ( ` <div class="mb-3 flex items-center justify-between"><h2 class="text-sm font-bold text-slate-600">月度签约趋势</h2><span class="text-xs text-slate-400">2026</span></div><div style="position:relative;height:200px"><canvas id="chartSign"></canvas></div> ` , "p-4" ) }