diff --git a/static/modules/expense.js b/static/modules/expense.js
index 515dd03..72b8d03 100644
--- a/static/modules/expense.js
+++ b/static/modules/expense.js
@@ -108,11 +108,12 @@ function renderExpense() {
}
// 模态框 monthOpts for form (with current value preselected)
+ var curMonth = thisYear + '-' + String(now.getMonth() + 1).padStart(2, '0');
var modalMonthOpts = '';
for (var yr2 = thisYear - 1; yr2 <= thisYear + 1; yr2++)
for (var m2 = 1; m2 <= 12; m2++) {
var mv2 = yr2 + '-' + String(m2).padStart(2, '0');
- modalMonthOpts += '';
+ modalMonthOpts += '';
}
var statusOpts = STATUS_OPTIONS.map(function(s) { return ''; }).join('');
diff --git a/static/modules/finance.js b/static/modules/finance.js
index cb14b86..0ac6907 100644
--- a/static/modules/finance.js
+++ b/static/modules/finance.js
@@ -144,7 +144,7 @@ function renderFinance() {
@@ -517,7 +517,7 @@ window.openFinanceModal = () => {
modal.classList.remove("hidden");
};
-window.addRevpayRow = (month = '', rev = '', gross = '', payment = '', rev_note = '') => {
+window.addRevpayRow = (month = new Date().getFullYear() + '-' + String(new Date().getMonth() + 1).padStart(2, '0'), rev = '', gross = '', payment = '', rev_note = '') => {
const tbody = document.querySelector("#revpayTbody");
if (!tbody) return;
const row = document.createElement("tr");
@@ -531,7 +531,7 @@ window.addRevpayRow = (month = '', rev = '', gross = '', payment = '', rev_note
if (window.lucide) window.lucide.createIcons();
};
-window.addCostRow = (month = '', expense_type = '', cost = '', paid = '', exp_note = '') => {
+window.addCostRow = (month = new Date().getFullYear() + '-' + String(new Date().getMonth() + 1).padStart(2, '0'), expense_type = '', cost = '', paid = '', exp_note = '') => {
const tbody = document.querySelector("#costTbody");
if (!tbody) return;
const row = document.createElement("tr");
@@ -1043,7 +1043,7 @@ function renderFinanceOverview() {
}
deptTbody += rowHtml + '';
}
- var deptCard = card('
业务线经营情况
毛利 - 平台费用 = 利润
' + deptThead + '' + deptTbody + '
', 'p-4');
+ var deptCard = card('
部门损益情况 部门利润 = 所有项目产生的毛利 - 部门 1 级产生的人力成本,研发成本,差旅和其他支出
' + deptThead + '' + deptTbody + '
', 'p-4');
// 业务线现金流卡片
var cfMonthly = [0,0,0,0,0,0,0,0,0,0,0,0];
@@ -1062,7 +1062,7 @@ function renderFinanceOverview() {
var cfRows = [
{ label: '项目现金流', vals: cfMonthly, annual: cfAnnual },
{ label: '平台费用(支出)', vals: expPaidMonthly, annual: expPaidAnnual },
- { label: '业务线现金流', vals: blCfMonthly, annual: blCfAnnual }
+ { label: '部门现金流', vals: blCfMonthly, annual: blCfAnnual }
];
var cfTbody = '';
for (var cfri = 0; cfri < 3; cfri++) {
@@ -1078,12 +1078,12 @@ function renderFinanceOverview() {
}
cfTbody += cfRowHtml + '';
}
- var cfCard = card('
业务线现金流
项目现金流 - 平台费用(支出)= 业务线现金流
' + deptThead + '' + cfTbody + '
', 'p-4');
+ var cfCard = card('
部门现金流 部门现金流=所有项目产生的现金流 - 部门一级因费用产生的现金流出或流入
' + deptThead + '' + cfTbody + '
', 'p-4');
document.querySelector("#financeOverview").innerHTML = '
' +
deptCard +
cfCard +
- card('
业务(项目)财务月度概览
合同 → 确收 → 毛利 → 成本 → 支出
' + thead + '' + tbody + '
', 'p-4') +
+ card('
项目经营详情 所有项目产生的签单,确收,毛利,回款,当期成本,当期流出,现金流
' + thead + '' + tbody + '
', 'p-4') +
'
' +
card('
月度签约趋势
2026', 'p-4') +
card('
月度确收与毛利
2026', 'p-4') +
@@ -1196,7 +1196,7 @@ function renderFinanceQuarterlyOverview() {
var cfRows = [
{ label: '项目现金流', vals: cfQ, annual: cfAnnual },
{ label: '平台费用(已付)', vals: expPaidQ, annual: expPaidAnnual },
- { label: '业务线现金流', vals: blCfQ, annual: blCfAnnual }
+ { label: '部门现金流', vals: blCfQ, annual: blCfAnnual }
];
var cfTbody = '';
for (var cfri = 0; cfri < 3; cfri++) {
@@ -1213,9 +1213,9 @@ function renderFinanceQuarterlyOverview() {
}
document.querySelector("#financeQuarterlyOverview").innerHTML = '
' +
- card('
业务(项目)财务季度概览
合同 → 确收 → 毛利 → 成本 → 支出 → 回款 → 项目现金流
' + thead + '' + tbody + '
', 'p-4') +
- card('
业务线经营情况
毛利 - 平台费用 = 利润
' + deptThead + '' + deptTbody + '
', 'p-4') +
- card('
业务线现金流
项目现金流 - 平台费用(已付)= 业务线现金流
' + deptThead + '' + cfTbody + '
', 'p-4') +
+ card('
项目经营详情 所有项目产生的签单,确收,毛利,回款,当期成本,当期流出,现金流
' + thead + '' + tbody + '
', 'p-4') +
+ card('
部门损益情况 部门利润 = 所有项目产生的毛利 - 部门 1 级产生的人力成本,研发成本,差旅和其他支出
' + deptThead + '' + deptTbody + '
', 'p-4') +
+ card('
部门现金流 部门现金流=所有项目产生的现金流 - 部门一级因费用产生的现金流出或流入
' + deptThead + '' + cfTbody + '
', 'p-4') +
'
';
if (window.lucide) window.lucide.createIcons();
}
diff --git a/static/modules/plan.js b/static/modules/plan.js
index e4d8f5c..4ed286f 100644
--- a/static/modules/plan.js
+++ b/static/modules/plan.js
@@ -143,7 +143,7 @@ function renderPlan() {
-
+
@@ -562,7 +562,7 @@ window.openPlanModal = () => {
modal.classList.remove("hidden");
};
-window.planAddRevpayRow = (month = '', rev = '', gross = '', payment = '', rev_note = '') => {
+window.planAddRevpayRow = (month = new Date().getFullYear() + '-' + String(new Date().getMonth() + 1).padStart(2, '0'), rev = '', gross = '', payment = '', rev_note = '') => {
const tbody = document.querySelector("#plan_revpayTbody");
if (!tbody) return;
const row = document.createElement("tr");
@@ -576,7 +576,7 @@ window.planAddRevpayRow = (month = '', rev = '', gross = '', payment = '', rev_n
if (window.lucide) window.lucide.createIcons();
};
-window.planAddCostRow = (month = '', expense_type = '', cost = '', paid = '', exp_note = '') => {
+window.planAddCostRow = (month = new Date().getFullYear() + '-' + String(new Date().getMonth() + 1).padStart(2, '0'), expense_type = '', cost = '', paid = '', exp_note = '') => {
const tbody = document.querySelector("#plan_costTbody");
if (!tbody) return;
const row = document.createElement("tr");
@@ -1133,7 +1133,7 @@ function renderPlanOverview() {
}
deptTbody += rowHtml + '';
}
- var deptCard = card('
业务线经营情况
毛利 - 平台费用 = 利润
' + deptThead + '' + deptTbody + '
', 'p-4');
+ var deptCard = card('
部门损益情况 部门利润 = 所有项目产生的毛利 - 部门 1 级产生的人力成本,研发成本,差旅和其他支出
' + deptThead + '' + deptTbody + '
', 'p-4');
// 业务线现金流卡片
@@ -1152,7 +1152,7 @@ function renderPlanOverview() {
var cfRows = [
{ label: '项目现金流', vals: cfMonthly, annual: cfAnnual },
{ label: '平台费用(已付)', vals: expPaidMonthly, annual: expPaidAnnual },
- { label: '业务线现金流', vals: blCfMonthly, annual: blCfAnnual }
+ { label: '部门现金流', vals: blCfMonthly, annual: blCfAnnual }
];
var cfTbody = '';
for (var cfri = 0; cfri < 3; cfri++) {
@@ -1168,12 +1168,12 @@ function renderPlanOverview() {
}
cfTbody += cfRowHtml + '';
}
- var cfCard = card('
业务线现金流
项目现金流 - 平台费用(已付)= 业务线现金流
' + deptThead + '' + cfTbody + '
', 'p-4');
+ var cfCard = card('
部门现金流 部门现金流=所有项目产生的现金流 - 部门一级因费用产生的现金流出或流入
' + deptThead + '' + cfTbody + '
', 'p-4');
document.querySelector("#planOverview").innerHTML = '
' +
deptCard +
cfCard +
- card('
业务(项目)财务概览
合同 → 确收 → 毛利 → 成本 → 已付
' + thead + '' + tbody + '
', 'p-4') +
+ card('
项目经营详情 所有项目产生的签单,确收,毛利,回款,当期成本,当期流出,现金流
' + thead + '' + tbody + '
', 'p-4') +
'
' +
card('
月度签约趋势
2026', 'p-4') +
card('
月度确收与毛利
2026', 'p-4') +
@@ -1289,7 +1289,7 @@ function renderPlanQuarterlyOverview() {
var cfRows = [
{ label: '项目现金流', vals: cfQ, annual: cfAnnual },
{ label: '平台费用(已付)', vals: expPaidQ, annual: expPaidAnnual },
- { label: '业务线现金流', vals: blCfQ, annual: blCfAnnual }
+ { label: '部门现金流', vals: blCfQ, annual: blCfAnnual }
];
var cfTbody = '';
for (var cfri = 0; cfri < 3; cfri++) {
@@ -1306,9 +1306,9 @@ function renderPlanQuarterlyOverview() {
}
document.querySelector("#planQuarterlyOverview").innerHTML = '
' +
- card('
业务线经营情况
毛利 - 平台费用 = 利润
' + deptThead + '' + deptTbody + '
', 'p-4') +
- card('
业务线现金流
项目现金流 - 平台费用(已付)= 业务线现金流
' + deptThead + '' + cfTbody + '
', 'p-4') +
- card('
业务(项目)财务季度概览
合同 → 确收 → 毛利 → 成本 → 支出 → 回款 → 项目现金流
' + thead + '' + tbody + '
', 'p-4') +
+ card('
部门损益情况 部门利润 = 所有项目产生的毛利 - 部门 1 级产生的人力成本,研发成本,差旅和其他支出
' + deptThead + '' + deptTbody + '
', 'p-4') +
+ card('
部门现金流 部门现金流=所有项目产生的现金流 - 部门一级因费用产生的现金流出或流入
' + deptThead + '' + cfTbody + '
', 'p-4') +
+ card('
项目经营详情 所有项目产生的签单,确收,毛利,回款,当期成本,当期流出,现金流
' + thead + '' + tbody + '
', 'p-4') +
'
';
if (window.lucide) window.lucide.createIcons();
}
diff --git a/static/modules/plan_expense.js b/static/modules/plan_expense.js
index ea0bc08..6847528 100644
--- a/static/modules/plan_expense.js
+++ b/static/modules/plan_expense.js
@@ -108,11 +108,12 @@ function renderPlanExpense() {
}
// 模态框 monthOpts for form (with current value preselected)
+ var curMonth = thisYear + '-' + String(now.getMonth() + 1).padStart(2, '0');
var modalMonthOpts = '
';
for (var yr2 = thisYear - 1; yr2 <= thisYear + 1; yr2++)
for (var m2 = 1; m2 <= 12; m2++) {
var mv2 = yr2 + '-' + String(m2).padStart(2, '0');
- modalMonthOpts += '
';
+ modalMonthOpts += '
';
}
var statusOpts = STATUS_OPTIONS.map(function(s) { return '
'; }).join('');
diff --git a/static/modules/utils.js b/static/modules/utils.js
index 73e055a..037730a 100644
--- a/static/modules/utils.js
+++ b/static/modules/utils.js
@@ -5,13 +5,13 @@ const state = {
data: null,
tenant: localStorage.getItem("opc-active-tenant") || "科普·无界",
opFilter: "all",
- finFilter: "projects",
+ finFilter: "overview",
selectedProject: null,
taskQuery: "",
taskView: localStorage.getItem("opc-task-view") || "detail",
finView: "overview",
finSort: null, // { key: 'col', asc: true }
- planFilter: "projects",
+ planFilter: "overview",
planYear: new Date().getFullYear(),
finYear: new Date().getFullYear(),
planStatusFilter: "all",
@@ -390,9 +390,10 @@ window.switchTenant = async (tenant) => {
localStorage.setItem("opc-active-tenant", tenant);
document.querySelector("#workspaceTitle").textContent = tenant.replace("·无界", "") + " OPC 工作台";
if (typeof updateTenantLabel === "function") updateTenantLabel();
+ state.planFilter = 'overview';
+ state.finFilter = 'overview';
updateSidebarTabs();
- if (tenant === "总览") { state.planFilter = 'overview'; state.finFilter = 'overview'; switchTab("home"); }
- else if (state.active === 'home') { state.active = 'plan'; localStorage.setItem("opc-active-tab", "plan"); document.querySelectorAll(".sidebar-tab").forEach((btn) => btn.classList.toggle("active", btn.dataset.tab === "plan")); document.querySelectorAll(".panel").forEach((panel) => panel.classList.toggle("active", panel.id === "plan")); }
+ if (state.active === 'home') { state.active = 'plan'; localStorage.setItem("opc-active-tab", "plan"); document.querySelectorAll(".sidebar-tab").forEach((btn) => btn.classList.toggle("active", btn.dataset.tab === "plan")); document.querySelectorAll(".panel").forEach((panel) => panel.classList.toggle("active", panel.id === "plan")); }
await load();
};
diff --git a/templates/index.html b/templates/index.html
index 5667480..adf544c 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -76,7 +76,7 @@
-
OPC Manager v1.2.0.20
+
OPC Manager v1.2.0.21