feat: 删除部门模块 + 任务系统重构 + 布局修复

- 删除部门(Home)侧边栏入口、面板及相关代码
- 删除 home.js,chartOptions 等图表工具迁移到 utils.js
- 清理 render()、togglePhase、filterPhaseTasks 等死代码
- 任务列表改为平铺(取消阶段分组),支持拖拽排序
- 任务表单加开始时间字段,重组字段布局为三列
- 任务展开面板改为竖排:时间、任务进展、卡点与备注
- 视图按钮和新增任务按钮移入任务卡片顶部
- 修复 index.html div 嵌套不平衡导致布局塌陷
- 修复 savedTab 校验和 switchTenant 侧边栏 active 同步
- 总览工作台只显示预算/发生总览入口
- 性能面板 id 去重
This commit is contained in:
mac
2026-07-15 14:49:12 +08:00
parent 39513c0a7b
commit ec457e9d40
9 changed files with 227 additions and 371 deletions

View File

@@ -1,7 +1,7 @@
// utils.js — 全局工具函数与共享状态
const state = {
active: "home",
active: "plan",
data: null,
tenant: localStorage.getItem("opc-active-tenant") || "科普·无界",
opFilter: "all",
@@ -120,7 +120,6 @@ function renderTable(headers, rows, rowClicks) {
}
var _loadingSteps = [
{ fn: 'renderHome', label: '正在加载首页仪表盘(指标卡片+图表)', skip: function() { return true; } },
{ fn: 'renderOverviewPlan', label: '正在加载预算总览', skip: function() { return state.tenant !== '总览'; } },
{ fn: 'renderOverviewFinance', label: '正在加载发生总览', skip: function() { return state.tenant !== '总览'; } },
{ fn: 'renderProjects', label: '正在加载业务机会列表' },
@@ -235,7 +234,7 @@ var _tabLoaded = {};
var _proposalsInitialized = false;
async function ensureTabData(tab) {
if (tab === 'home' || tab === 'performance' || tab === 'overview_plan' || tab === 'overview_finance') return;
if (tab === 'performance' || tab === 'overview_plan' || tab === 'overview_finance') return;
var resource = _tabResourceMap[tab];
if (!resource) return;
var dataKey = resource;
@@ -249,6 +248,8 @@ async function ensureTabData(tab) {
try { state.data.expense = await api("/api/expense/list?tenant=" + encodeURIComponent(state.tenant)); } catch(e) {}
try { state.data.finance = await api("/api/finance/list?tenant=" + encodeURIComponent(state.tenant)); } catch(e) {}
try { state.data.tasks = await api("/api/tasks/list?tenant=" + encodeURIComponent(state.tenant)); } catch(e) {}
} else if (tab === 'projects') {
try { state.data.tasks = await api("/api/tasks/list?tenant=" + encodeURIComponent(state.tenant)); } catch(e) {}
} else if (tab === 'plan') {
try { state.data.planExpense = await api("/api/planExpense/list?tenant=" + encodeURIComponent(state.tenant)); } catch(e) {}
}
@@ -265,7 +266,7 @@ function switchTab(tab) {
document.querySelectorAll(".panel").forEach((panel) => panel.classList.toggle("active", panel.id === tab));
// 更新顶部标题
const titles = { home: 'OPC 工作台', finance: '执行管理', plan: '预算管理', projects: '重点工作台账', proposals: '业务方案', products: '版本与运营', performance: '季度绩效考核', overview_plan: '预算总览', overview_finance: '发生总览' };
const titles = { finance: '执行管理', plan: '预算管理', projects: '重点工作台账', proposals: '业务方案', products: '版本与运营', performance: '季度绩效考核', overview_plan: '预算总览', overview_finance: '发生总览' };
const titleEl = document.querySelector('#workspaceTitle');
if (titleEl) titleEl.textContent = titles[tab] || state.tenant + ' OPC 工作台';
@@ -283,28 +284,15 @@ function updateSidebarTabs() {
if (isOverview) {
btn.style.display = (tab === "overview_plan" || tab === "overview_finance") ? "" : "none";
} else {
btn.style.display = (tab === "overview_plan" || tab === "overview_finance" || tab === "home") ? "none" : "";
btn.style.display = (tab === "overview_plan" || tab === "overview_finance") ? "none" : "";
}
});
}
function render() {
if (!state.data) return;
if (state.tenant === '总览') renderHome();
renderProjects();
renderProposals();
renderProducts();
renderPerformance();
renderFinance();
renderPlan();
if (window.lucide) window.lucide.createIcons();
}
function renderActive() {
if (!state.data) return;
const tab = state.active;
if (tab === "home") renderHome();
else if (tab === "overview_plan") renderOverviewPlan();
if (tab === "overview_plan") renderOverviewPlan();
else if (tab === "overview_finance") renderOverviewFinance();
else if (tab === "projects") renderProjects();
else if (tab === "proposals") renderProposals();
@@ -403,11 +391,14 @@ window.switchTenant = async (tenant) => {
localStorage.setItem("opc-active-tab", "overview_plan");
document.querySelectorAll(".sidebar-tab").forEach((btn) => btn.classList.toggle("active", btn.dataset.tab === "overview_plan"));
document.querySelectorAll(".panel").forEach((panel) => panel.classList.toggle("active", panel.id === "overview_plan"));
} else if (state.active === 'home' || state.active === 'overview_plan' || state.active === 'overview_finance') {
} else if (state.active === 'overview_plan' || state.active === 'overview_finance') {
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"));
} else {
document.querySelectorAll(".sidebar-tab").forEach((btn) => btn.classList.toggle("active", btn.dataset.tab === state.active));
document.querySelectorAll(".panel").forEach((panel) => panel.classList.toggle("active", panel.id === state.active));
}
await load();
};
@@ -424,3 +415,18 @@ window.doLogout = async () => {
await api("/api/auth/logout", { method: "POST" });
location.href = "/login";
};
// 图表工具函数(曾被 home.js 中 plan/finance 模块复用)
const moneyTick = (v) => v >= 10000 ? (v / 10000).toFixed(0) + "万" : v;
const monthLabels = (data) => data.map((x) => parseInt(x.month.split("-")[1]) + "月");
function chartOptions(yCallback) {
return {
responsive: true,
maintainAspectRatio: false,
plugins: { legend: { position: "bottom", labels: { boxWidth: 12, font: { size: 11 } } } },
scales: {
x: { ticks: { font: { size: 10 } }, grid: { display: false } },
y: { ticks: { font: { size: 11 }, callback: yCallback } },
},
};
}