feat: 经营报表年份支持 + 项目管理年份过滤修复

- 经营月报/季报增加年份选择入口,数据按选中年份过滤
- 年份下拉框扩展至 2020-2027,增加「所有年份」选项
- 项目管理视图全年/季度/月度均按年份过滤项目列表
- 修复月度视图在所有年份模式下数据查询(substring→slice)
- 修复 finView/finFilter 初始化,确保全年标签默认选中
- 修复 yearly API 缺失 tenant 参数导致跨工作台数据错误
- 费用数据(expense)遍历加年份过滤,季报指标改为从 fm 累加
This commit is contained in:
mac
2026-07-14 15:25:35 +08:00
parent f619ed34a7
commit d2d1b0f99e
4 changed files with 163 additions and 51 deletions

View File

@@ -1036,10 +1036,10 @@ window.deletePlanItem = async () => {
// 从 planFinances 计算月度数据
function computePlanMonthly(planFinances) {
function computePlanMonthly(planFinances, year) {
var pfs = planFinances || [];
var months = [];
var year = new Date().getFullYear();
year = 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++) {
@@ -1062,7 +1062,7 @@ function computePlanMonthly(planFinances) {
// 总览渲染
function renderPlanOverview() {
const planFinances = state.data.planFinances || [];
const fm = computePlanMonthly(planFinances);
const fm = computePlanMonthly(planFinances, state.planYear);
const moneyIntL = (v) => Math.round(Number(v || 0)).toLocaleString("zh-CN");
const moneyWan = (v) => {
const n = Number(v || 0);
@@ -1180,9 +1180,9 @@ function renderPlanOverview() {
cfCard +
card('<h3 class="text-base font-bold text-slate-700 mb-3">项目经营详情 <span class="text-sm text-slate-500 font-normal ml-3">所有项目产生的签单,确收,毛利,回款,成本,支出,现金流</span></h3><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-3 gap-2.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-600">2026</span></div><div style="position:relative;height:200px"><canvas id="planChartSign"></canvas></div>', 'p-4') +
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-600">2026</span></div><div style="position:relative;height:200px"><canvas id="planChartRev"></canvas></div>', 'p-4') +
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-600">2026</span></div><div style="position:relative;height:200px"><canvas id="planChartCash"></canvas></div>', 'p-4') +
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-600">' + state.planYear + '</span></div><div style="position:relative;height:200px"><canvas id="planChartSign"></canvas></div>', 'p-4') +
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-600">' + state.planYear + '</span></div><div style="position:relative;height:200px"><canvas id="planChartRev"></canvas></div>', 'p-4') +
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-600">' + state.planYear + '</span></div><div style="position:relative;height:200px"><canvas id="planChartCash"></canvas></div>', 'p-4') +
'</div></div>';
if (window.lucide) window.lucide.createIcons();
@@ -1195,7 +1195,7 @@ function renderPlanOverview() {
function renderPlanQuarterlyOverview() {
const planFinances = state.data.planFinances || [];
const fm = computePlanMonthly(planFinances);
const fm = computePlanMonthly(planFinances, state.planYear);
const moneyIntL = (v) => Math.round(Number(v || 0)).toLocaleString("zh-CN");
const card = (body, cls) => '<div class="card ' + (cls || 'p-4') + '">' + body + '</div>';
var annualSums2 = { sign: 0, revenue: 0, gross: 0, cost: 0, payment: 0, paid: 0 };