feat(alert): 异常浮动新行为——24h过滤+新异常3秒展开折叠+已展开不重复+首次加载不弹旧异常
This commit is contained in:
+45
-16
@@ -3077,16 +3077,40 @@ function toggleAlertFloat(ev) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderAlerts(alerts) {
|
function renderAlerts(alerts) {
|
||||||
|
// 首次加载初始化:把当前已有异常标记为"已展开",避免打开页面就弹旧异常
|
||||||
|
if (!localStorage.getItem('alertsInitialized')) {
|
||||||
|
try {
|
||||||
|
const initKeys = (Array.isArray(alerts)?alerts:[]).map(a => (a.ts||0)+'_'+(a.source||'')+'_'+(a.code||''));
|
||||||
|
localStorage.setItem('expandedAlertKeys', JSON.stringify(initKeys));
|
||||||
|
localStorage.setItem('alertsInitialized', '1');
|
||||||
|
} catch(e) {}
|
||||||
|
}
|
||||||
const el = document.getElementById('alertFloat');
|
const el = document.getElementById('alertFloat');
|
||||||
const body = document.getElementById('alertBody');
|
const body = document.getElementById('alertBody');
|
||||||
const countEl = document.getElementById('alertCount');
|
const countEl = document.getElementById('alertCount');
|
||||||
const list = Array.isArray(alerts) ? alerts : [];
|
const list = Array.isArray(alerts) ? alerts : [];
|
||||||
// 只显示 error/critical/warning(info 不打扰)
|
// 只显示 error/critical/warning(info 不打扰)
|
||||||
const shown = list.filter(a => a.level !== 'info');
|
const shown = list.filter(a => a.level !== 'info');
|
||||||
const keys = shown.map(a => a.ts + '_' + a.source + '_' + a.code).join('|');
|
|
||||||
|
|
||||||
if (!shown.length) {
|
// ── 24小时过滤:只有24小时内的异常才算"最新异常",有资格右上角显示 ──
|
||||||
// 无异常 → 整个浮窗隐藏(2026-08-13 老莫反馈:无异常不应显示红底感叹号)
|
const nowSec = Date.now() / 1000;
|
||||||
|
const fresh = shown.filter(a => (a.ts || 0) > nowSec - 86400);
|
||||||
|
|
||||||
|
// 已展开过的异常 keys(localStorage 持久化,跨会话记住,旧异常不再触发展开)
|
||||||
|
let expandedKeys = new Set();
|
||||||
|
try { expandedKeys = new Set(JSON.parse(localStorage.getItem('expandedAlertKeys') || '[]')); } catch(e) {}
|
||||||
|
// 清理过期的已展开记录(24小时前的清掉,避免无限增长)
|
||||||
|
const expandedArr = [...expandedKeys];
|
||||||
|
|
||||||
|
const freshKeys = fresh.map(a => (a.ts||0) + '_' + (a.source||'') + '_' + (a.code||''));
|
||||||
|
const freshKeySet = new Set(freshKeys);
|
||||||
|
|
||||||
|
// 找出"新异常":在24小时内,且从未被展开过
|
||||||
|
const newKeys = freshKeys.filter(k => !expandedKeys.has(k));
|
||||||
|
const hasNew = newKeys.length > 0;
|
||||||
|
|
||||||
|
if (!fresh.length) {
|
||||||
|
// 无最新异常 → 隐藏浮窗
|
||||||
el.style.display = 'none';
|
el.style.display = 'none';
|
||||||
el.classList.add('collapsed');
|
el.classList.add('collapsed');
|
||||||
body.style.display = 'none';
|
body.style.display = 'none';
|
||||||
@@ -3096,29 +3120,27 @@ function renderAlerts(alerts) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 有异常 → 显示浮窗
|
// 有最新异常 → 显示浮窗
|
||||||
el.style.display = '';
|
el.style.display = '';
|
||||||
|
|
||||||
// 新异常 → 自动展开几秒后折叠
|
|
||||||
const isNew = keys !== lastAlertKeys;
|
|
||||||
lastAlertKeys = keys;
|
|
||||||
|
|
||||||
countEl.style.display = 'inline-block';
|
countEl.style.display = 'inline-block';
|
||||||
countEl.textContent = shown.length;
|
countEl.textContent = fresh.length;
|
||||||
|
|
||||||
const levelIcon = { critical: '🔴', error: '🟠', warning: '🟡' };
|
const levelIcon = { critical: '🔴', error: '🟠', warning: '🟡' };
|
||||||
body.innerHTML = shown.map(a =>
|
body.innerHTML = fresh.map(a =>
|
||||||
`<div class="alert-item ${a.level || 'error'}">
|
`<div class="alert-item ${a.level || 'error'}">
|
||||||
<div><span class="a-src">${levelIcon[a.level]||'🟠'} ${a.source||''}</span>
|
<div><span class="a-src">${levelIcon[a.level]||'🟠'} ${a.source||''}</span>
|
||||||
${a.code ? `<span class="font-mono text-slate-500">${a.code}</span>` : ''}</div>
|
${a.code ? `<span class="font-mono text-slate-500">${a.code}</span>` : ''}</div>
|
||||||
<div class="a-title">${a.title || ''}</div>
|
<div class="a-title">${esc(a.title || '')}</div>
|
||||||
${a.detail ? `<div class="a-detail">${a.detail}</div>` : ''}
|
${a.detail ? `<div class="a-detail">${esc(a.detail)}</div>` : ''}
|
||||||
<div class="text-slate-600 text-[10px]">${a.ts_str || ''}</div>
|
<div class="text-slate-600 text-[10px]">${a.ts_str || ''}</div>
|
||||||
</div>`
|
</div>`
|
||||||
).join('');
|
).join('');
|
||||||
|
|
||||||
// 折叠态且新消息 → 展开 5 秒自动收起
|
// ── 展开逻辑:只有"新异常"(未展开过)才触发自动展开 ──
|
||||||
if (isNew && el.classList.contains('collapsed')) {
|
const isCurrentlyCollapsed = el.classList.contains('collapsed');
|
||||||
|
|
||||||
|
if (hasNew && isCurrentlyCollapsed) {
|
||||||
|
// 展开 3 秒后自动折叠
|
||||||
el.classList.remove('collapsed');
|
el.classList.remove('collapsed');
|
||||||
body.style.display = 'block';
|
body.style.display = 'block';
|
||||||
el.querySelector('.alert-toggle').textContent = '▴';
|
el.querySelector('.alert-toggle').textContent = '▴';
|
||||||
@@ -3128,8 +3150,15 @@ function renderAlerts(alerts) {
|
|||||||
body.style.display = 'none';
|
body.style.display = 'none';
|
||||||
el.querySelector('.alert-toggle').textContent = '▾';
|
el.querySelector('.alert-toggle').textContent = '▾';
|
||||||
alertAutoHideTimer = null;
|
alertAutoHideTimer = null;
|
||||||
}, 5000);
|
}, 3000);
|
||||||
|
|
||||||
|
// 把这些新异常标记为"已展开过"(持久化,之后不再触发)
|
||||||
|
newKeys.forEach(k => expandedKeys.add(k));
|
||||||
|
try { localStorage.setItem('expandedAlertKeys', JSON.stringify([...expandedKeys])); } catch(e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lastAlertKeys = freshKeys.join('|');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// refreshAll 内联渲染:把 alerts 交给 renderAlerts
|
// refreshAll 内联渲染:把 alerts 交给 renderAlerts
|
||||||
|
|||||||
Reference in New Issue
Block a user