feat: 加载浮层+工作台改回下拉菜单
- load()增加模态加载浮层: 7步进度展示+进度条+逐步渲染 - 工作台切换从竖向平铺改回下拉菜单(带图标) - 版本号 v1.0.0.39
This commit is contained in:
@@ -115,18 +115,81 @@ function renderTable(headers, rows, rowClicks) {
|
||||
`);
|
||||
}
|
||||
|
||||
var _loadingSteps = [
|
||||
{ fn: 'renderHome', label: '正在加载首页仪表盘(指标卡片+图表)' },
|
||||
{ fn: 'renderProjects', label: '正在加载业务机会列表' },
|
||||
{ fn: 'renderProposals', label: '正在加载业务方案列表' },
|
||||
{ fn: 'renderProducts', label: '正在加载产品迭代列表' },
|
||||
{ fn: 'renderPerformance', label: '正在加载绩效管理' },
|
||||
{ fn: 'renderFinance', label: '正在加载财务模块(表格+总览+图表)' },
|
||||
{ fn: 'renderPlan', label: '正在加载计划预算' },
|
||||
];
|
||||
|
||||
function showLoadingOverlay(steps) {
|
||||
var existing = document.getElementById('_loadingOverlay');
|
||||
if (existing) existing.remove();
|
||||
var stepsHtml = steps.map(function(s, i) {
|
||||
return '<div id="_loadingStep_' + i + '" class="flex items-center gap-3 py-1.5 text-sm ' + (i === 0 ? 'text-blue-600 font-medium' : 'text-slate-400') + '">' +
|
||||
'<span class="w-4 h-4 flex items-center justify-center">' + (i === 0 ? '<svg class="animate-spin" width="14" height="14" viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="3" opacity="0.25"/><path d="M12 2a10 10 0 0 1 10 10" stroke="currentColor" stroke-width="3" stroke-linecap="round"/></svg>' : '<span class="w-2 h-2 rounded-full bg-slate-300"></span>') + '</span>' +
|
||||
'<span>' + s.label + '</span>' +
|
||||
'</div>';
|
||||
}).join('');
|
||||
var overlay = document.createElement('div');
|
||||
overlay.id = '_loadingOverlay';
|
||||
overlay.className = 'fixed inset-0 z-[99999] flex items-center justify-center bg-black/50';
|
||||
overlay.innerHTML = '<div class="bg-white rounded-2xl shadow-2xl px-8 py-6 w-full max-w-md">' +
|
||||
'<h3 class="text-base font-bold text-slate-800 mb-1">正在加载工作台</h3>' +
|
||||
'<p class="text-xs text-slate-400 mb-4">共 ' + steps.length + ' 个模块,请稍候…</p>' +
|
||||
'<div id="_loadingSteps">' + stepsHtml + '</div>' +
|
||||
'<div class="mt-4 h-1 bg-slate-100 rounded-full overflow-hidden"><div id="_loadingProgress" class="h-full bg-blue-600 transition-all duration-300" style="width:0%"></div></div>' +
|
||||
'</div>';
|
||||
document.body.appendChild(overlay);
|
||||
}
|
||||
|
||||
function updateLoadingStep(idx, total) {
|
||||
var stepEl = document.getElementById('_loadingStep_' + idx);
|
||||
if (stepEl) {
|
||||
stepEl.className = 'flex items-center gap-3 py-1.5 text-sm text-green-600 font-medium';
|
||||
stepEl.querySelector('span:first-child').innerHTML = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>';
|
||||
}
|
||||
var nextEl = document.getElementById('_loadingStep_' + (idx + 1));
|
||||
if (nextEl) {
|
||||
nextEl.className = 'flex items-center gap-3 py-1.5 text-sm text-blue-600 font-medium';
|
||||
nextEl.querySelector('span:first-child').innerHTML = '<svg class="animate-spin" width="14" height="14" viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="3" opacity="0.25"/><path d="M12 2a10 10 0 0 1 10 10" stroke="currentColor" stroke-width="3" stroke-linecap="round"/></svg>';
|
||||
}
|
||||
var progress = document.getElementById('_loadingProgress');
|
||||
if (progress) progress.style.width = Math.round((idx + 1) / total * 100) + '%';
|
||||
}
|
||||
|
||||
function hideLoadingOverlay() {
|
||||
var overlay = document.getElementById('_loadingOverlay');
|
||||
if (overlay) overlay.remove();
|
||||
}
|
||||
|
||||
async function load() {
|
||||
showLoadingOverlay(_loadingSteps);
|
||||
state.data = await api(`/api/bootstrap?tenant=${encodeURIComponent(state.tenant)}`);
|
||||
// 首次加载时确保标准资料库 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
|
||||
}
|
||||
}
|
||||
render();
|
||||
// 逐步渲染
|
||||
for (var i = 0; i < _loadingSteps.length; i++) {
|
||||
var step = _loadingSteps[i];
|
||||
if (typeof window[step.fn] === 'function') {
|
||||
window[step.fn]();
|
||||
}
|
||||
updateLoadingStep(i, _loadingSteps.length);
|
||||
await new Promise(function(r) { setTimeout(r, 50); });
|
||||
}
|
||||
if (window.lucide) window.lucide.createIcons();
|
||||
setTimeout(hideLoadingOverlay, 300);
|
||||
}
|
||||
|
||||
function switchTab(tab) {
|
||||
|
||||
Reference in New Issue
Block a user