|
|
|
|
@@ -109,7 +109,7 @@ function renderPlan() {
|
|
|
|
|
const activeQ = state.planQuarter !== undefined ? state.planQuarter : Math.floor(nowD.getMonth() / 3);
|
|
|
|
|
const activeMonths = qMonths[activeQ];
|
|
|
|
|
const yearOpts = [2024,2025,2026,2027];
|
|
|
|
|
const finHeaderBase = `<div class="flex items-center gap-2"><button onclick="setPlanView('overview')" class="px-3 py-0.5 rounded text-sm font-medium ${state.planView==='overview'?'bg-blue-600 text-white':'bg-slate-100 text-slate-600 hover:bg-slate-200'}">总视图</button><span class="text-slate-300 mx-2">|</span><span class="text-sm text-slate-500">年份:</span><select onchange="setPlanYear(this.value)" class="px-2 py-0.5 rounded text-sm font-medium border border-slate-200 bg-white">${yearOpts.map(y => `<option value="${y}" ${state.planYear===y?'selected':''}>${y}</option>`).join('')}</select><span class="text-slate-300 mx-2">|</span><span class="text-sm text-slate-500">季度:</span>${qLabels.map((q,i) => `<button onclick="setPlanQuarter(${i})" class="px-3 py-0.5 rounded text-sm font-medium ${state.planView==='quarterly'&&activeQ===i?'bg-blue-600 text-white':'bg-slate-100 text-slate-600 hover:bg-slate-200'}">${q}</button>`).join('')}<span class="text-slate-300 mx-2">|</span><span class="text-sm text-slate-500">月度:</span>${activeMonths.map(m => { const ms = `${state.planYear}-${String(m).padStart(2,'0')}`; return `<button onclick="setPlanMonth('${ms}')" class="px-3 py-0.5 rounded text-sm font-medium ${state.planView==='monthly'&&state.planMonth===ms?'bg-blue-600 text-white':'bg-slate-100 text-slate-600 hover:bg-slate-200'}">${m}月</button>`; }).join('')}</div>`;
|
|
|
|
|
const finHeaderBase = `<div class="flex items-center gap-2"><button onclick="setPlanView('overview')" class="px-3 py-0.5 rounded text-sm font-medium ${state.planView==='overview'?'bg-blue-600 text-white':'bg-slate-100 text-slate-600 hover:bg-slate-200'}">总视图</button><span class="text-slate-300 mx-2">|</span><span class="text-sm text-slate-500">年份:</span><select onchange="setPlanYear(this.value)" class="px-2 py-0.5 rounded text-sm font-medium border border-slate-200 bg-white">${yearOpts.map(y => `<option value="${y}" ${state.planYear===y?'selected':''}>${y}</option>`).join('')}</select><span class="text-slate-300 mx-2">|</span><span class="text-sm text-slate-500">季度:</span>${qLabels.map((q,i) => `<button onclick="setPlanQuarter(${i})" class="px-3 py-0.5 rounded text-sm font-medium ${state.planView==='quarterly'&&activeQ===i?'bg-blue-600 text-white':'bg-slate-100 text-slate-600 hover:bg-slate-200'}">${q}</button>`).join('')}<span class="text-slate-300 mx-2">|</span><span class="text-sm text-slate-500">月度:</span>${activeMonths.map(m => { const ms = `${state.planYear}-${String(m).padStart(2,'0')}`; return `<button onclick="setPlanMonth('${ms}')" class="px-3 py-0.5 rounded text-sm font-medium ${state.planView==='monthly'&&state.planMonth===ms?'bg-blue-600 text-white':'bg-slate-100 text-slate-600 hover:bg-slate-200'}">${m}月</button>`; }).join('')}<span class="text-slate-300 mx-2">|</span><button onclick="setPlanStatusFilter('unsigned')" class="px-3 py-0.5 rounded text-sm font-medium ${state.planStatusFilter==='unsigned'?'bg-blue-600 text-white':'bg-slate-100 text-slate-600 hover:bg-slate-200'}">待签约</button><button onclick="setPlanStatusFilter('signed')" class="px-3 py-0.5 rounded text-sm font-medium ${state.planStatusFilter==='signed'?'bg-blue-600 text-white':'bg-slate-100 text-slate-600 hover:bg-slate-200'}">已签约</button><button onclick="setPlanStatusFilter('paymentonly')" class="px-3 py-0.5 rounded text-sm font-medium ${state.planStatusFilter==='paymentonly'?'bg-blue-600 text-white':'bg-slate-100 text-slate-600 hover:bg-slate-200'}">只付款</button></div>`;
|
|
|
|
|
const finAddBtn = `<button class="btn btn-primary btn-sm" onclick="openPlanModal()">新增财务项目</button>`;
|
|
|
|
|
|
|
|
|
|
const isOverviewMode = false;
|
|
|
|
|
@@ -345,6 +345,21 @@ function renderPlan() {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const fmtNoUnit = (v) => v ? `<span class="font-medium">${Number(v||0).toLocaleString('zh-CN')}</span>` : '<span class="text-slate-300">—</span>';
|
|
|
|
|
|
|
|
|
|
// 状态过滤函数
|
|
|
|
|
const filterByStatus = (items) => {
|
|
|
|
|
var sf = state.planStatusFilter || 'all';
|
|
|
|
|
if (sf === 'all') return items;
|
|
|
|
|
return items.filter(d => {
|
|
|
|
|
if (sf === 'unsigned') return (d.pf.project_type || '待签约') === '待签约';
|
|
|
|
|
if (sf === 'signed') return (d.pf.project_type || '待签约') === '已签约';
|
|
|
|
|
if (sf === 'paymentonly') {
|
|
|
|
|
return (!d.rev && !d.gross && !d.payment) && (d.cost || d.paid);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const tdRow = (pf, rev, payment, cost, paid, gross) => {
|
|
|
|
|
const cashflow = payment - paid;
|
|
|
|
|
const payRVal = rev && payment ? Math.round(payment / rev * 100) : null;
|
|
|
|
|
@@ -422,7 +437,7 @@ function renderPlan() {
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
var sortK = state.planSort && state.planSort.key ? state.planSort.key.split('|')[1] : null;
|
|
|
|
|
dataItems = sortData(dataItems, sortK);
|
|
|
|
|
dataItems = filterByStatus(sortData(dataItems, sortK));
|
|
|
|
|
const rows = [];
|
|
|
|
|
let sumRev = 0, sumPay = 0, sumCost = 0, sumPaid = 0, sumGross = 0;
|
|
|
|
|
dataItems.forEach(d => {
|
|
|
|
|
@@ -477,7 +492,7 @@ function renderPlan() {
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
var sortK = state.planSort && state.planSort.key ? state.planSort.key.split('|')[1] : null;
|
|
|
|
|
dataItems = sortData(dataItems, sortK);
|
|
|
|
|
dataItems = filterByStatus(sortData(dataItems, sortK));
|
|
|
|
|
let sumRev = 0, sumPay = 0, sumCost = 0, sumPaid = 0, sumGross = 0;
|
|
|
|
|
const rows = [];
|
|
|
|
|
dataItems.forEach(d => {
|
|
|
|
|
@@ -518,7 +533,7 @@ function renderPlan() {
|
|
|
|
|
});
|
|
|
|
|
var sortK = null;
|
|
|
|
|
if (state.planSort && state.planSort.key && state.planSort.key.startsWith('sig|')) sortK = state.planSort.key.split('|')[1];
|
|
|
|
|
dataItems = sortData(dataItems, sortK);
|
|
|
|
|
dataItems = filterByStatus(sortData(dataItems, sortK));
|
|
|
|
|
let sumRev = 0, sumPay = 0, sumCost = 0, sumPaid = 0, sumGross = 0;
|
|
|
|
|
const rows = [];
|
|
|
|
|
dataItems.forEach(d => {
|
|
|
|
|
|