|
|
|
|
@@ -185,15 +185,22 @@ async function load() {
|
|
|
|
|
if (!state.data.planExpense) state.data.planExpense = [];
|
|
|
|
|
clearTabCache();
|
|
|
|
|
updateLoadingStep(0, allSteps.length);
|
|
|
|
|
// 首次加载时确保标准资料库 7 项已初始化
|
|
|
|
|
if (typeof ensureStandardProposals === "function") {
|
|
|
|
|
const existing = (state.data.proposals || []).filter(p => p.proposal_type === "标准资料");
|
|
|
|
|
const missingCount = 7 - existing.length;
|
|
|
|
|
if (missingCount > 0) {
|
|
|
|
|
hideLoadingOverlay();
|
|
|
|
|
await ensureStandardProposals();
|
|
|
|
|
return; // ensureStandardProposals 内部会再次 render
|
|
|
|
|
}
|
|
|
|
|
// 按需加载当前 tab 的数据(必须在 ensureStandardProposals 之前,否则会被 return 跳过)
|
|
|
|
|
await ensureTabData(state.active);
|
|
|
|
|
// 首次加载时确保标准资料库 7 项已初始化(仅首次,避免每次切换工作台都触发)
|
|
|
|
|
if (!_proposalsInitialized && typeof ensureStandardProposals === "function") {
|
|
|
|
|
_proposalsInitialized = true;
|
|
|
|
|
try {
|
|
|
|
|
const proposalsData = await api("/api/proposals/list?tenant=" + encodeURIComponent(state.tenant));
|
|
|
|
|
state.data.proposals = proposalsData;
|
|
|
|
|
const existing = (proposalsData || []).filter(p => p.proposal_type === "标准资料");
|
|
|
|
|
const missingCount = 7 - existing.length;
|
|
|
|
|
if (missingCount > 0) {
|
|
|
|
|
hideLoadingOverlay();
|
|
|
|
|
await ensureStandardProposals();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} catch(e) { /* non-critical */ }
|
|
|
|
|
}
|
|
|
|
|
// 逐步渲染
|
|
|
|
|
for (var i = 0; i < _loadingSteps.length; i++) {
|
|
|
|
|
@@ -221,6 +228,7 @@ var _tabResourceMap = {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var _tabLoaded = {};
|
|
|
|
|
var _proposalsInitialized = false;
|
|
|
|
|
|
|
|
|
|
async function ensureTabData(tab) {
|
|
|
|
|
if (tab === 'home' || tab === 'performance') return;
|
|
|
|
|
@@ -231,10 +239,12 @@ async function ensureTabData(tab) {
|
|
|
|
|
_tabLoaded[dataKey + '_' + state.tenant] = true;
|
|
|
|
|
try {
|
|
|
|
|
state.data[dataKey] = await api("/api/" + resource + "/list?tenant=" + encodeURIComponent(state.tenant));
|
|
|
|
|
} catch(e) { /* non-critical */ }
|
|
|
|
|
} catch(e) { console.error('ensureTabData failed:', resource, e.message); }
|
|
|
|
|
// Load related expense data for finance/plan tabs
|
|
|
|
|
if (tab === 'finance') {
|
|
|
|
|
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 === 'plan') {
|
|
|
|
|
try { state.data.planExpense = await api("/api/planExpense/list?tenant=" + encodeURIComponent(state.tenant)); } catch(e) {}
|
|
|
|
|
}
|
|
|
|
|
@@ -356,7 +366,7 @@ window.setPlanSort = (key) => {
|
|
|
|
|
else { state.planSort.key = key; state.planSort.asc = true; }
|
|
|
|
|
renderPlan();
|
|
|
|
|
};
|
|
|
|
|
window.switchTenant = (tenant) => {
|
|
|
|
|
window.switchTenant = async (tenant) => {
|
|
|
|
|
state.tenant = tenant;
|
|
|
|
|
state.selectedProject = null;
|
|
|
|
|
localStorage.setItem("opc-active-tenant", tenant);
|
|
|
|
|
@@ -364,7 +374,8 @@ window.switchTenant = (tenant) => {
|
|
|
|
|
if (typeof updateTenantLabel === "function") updateTenantLabel();
|
|
|
|
|
updateSidebarTabs();
|
|
|
|
|
if (tenant === "总览") { state.planFilter = 'overview'; state.finFilter = 'overview'; switchTab("home"); }
|
|
|
|
|
load();
|
|
|
|
|
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")); }
|
|
|
|
|
await load();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 轻量刷新辅助函数
|
|
|
|
|
|