feat(alert): 异常浮动新行为——24h过滤+新异常3秒展开折叠+已展开不重复+首次加载不弹旧异常

This commit is contained in:
xxm
2026-08-22 09:56:43 +08:00
parent c93dcdf8ab
commit 26d751b071
+45 -16
View File
@@ -3077,16 +3077,40 @@ function toggleAlertFloat(ev) {
}
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 body = document.getElementById('alertBody');
const countEl = document.getElementById('alertCount');
const list = Array.isArray(alerts) ? alerts : [];
// 只显示 error/critical/warninginfo 不打扰)
const shown = list.filter(a => a.level !== 'info');
const keys = shown.map(a => a.ts + '_' + a.source + '_' + a.code).join('|');
if (!shown.length) {
// 无异常 → 整个浮窗隐藏(2026-08-13 老莫反馈:无异常不应显示红底感叹号)
// ── 24小时过滤:只有24小时内的异常才算"最新异常",有资格右上角显示 ──
const nowSec = Date.now() / 1000;
const fresh = shown.filter(a => (a.ts || 0) > nowSec - 86400);
// 已展开过的异常 keyslocalStorage 持久化,跨会话记住,旧异常不再触发展开)
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.classList.add('collapsed');
body.style.display = 'none';
@@ -3096,29 +3120,27 @@ function renderAlerts(alerts) {
return;
}
// 有异常 → 显示浮窗
// 有最新异常 → 显示浮窗
el.style.display = '';
// 新异常 → 自动展开几秒后折叠
const isNew = keys !== lastAlertKeys;
lastAlertKeys = keys;
countEl.style.display = 'inline-block';
countEl.textContent = shown.length;
countEl.textContent = fresh.length;
const levelIcon = { critical: '🔴', error: '🟠', warning: '🟡' };
body.innerHTML = shown.map(a =>
body.innerHTML = fresh.map(a =>
`<div class="alert-item ${a.level || 'error'}">
<div><span class="a-src">${levelIcon[a.level]||'🟠'} ${a.source||''}</span>
${a.code ? `<span class="font-mono text-slate-500">${a.code}</span>` : ''}</div>
<div class="a-title">${a.title || ''}</div>
${a.detail ? `<div class="a-detail">${a.detail}</div>` : ''}
<div class="a-title">${esc(a.title || '')}</div>
${a.detail ? `<div class="a-detail">${esc(a.detail)}</div>` : ''}
<div class="text-slate-600 text-[10px]">${a.ts_str || ''}</div>
</div>`
).join('');
// 折叠态且新消息 → 展开 5 秒自动收起
if (isNew && el.classList.contains('collapsed')) {
// ── 展开逻辑:只有"新异常"(未展开过)才触发自动展开 ──
const isCurrentlyCollapsed = el.classList.contains('collapsed');
if (hasNew && isCurrentlyCollapsed) {
// 展开 3 秒后自动折叠
el.classList.remove('collapsed');
body.style.display = 'block';
el.querySelector('.alert-toggle').textContent = '▴';
@@ -3128,8 +3150,15 @@ function renderAlerts(alerts) {
body.style.display = 'none';
el.querySelector('.alert-toggle').textContent = '▾';
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