优化 职务图标 文字提示

This commit is contained in:
2026-04-22 10:18:49 +08:00
parent bef797abd5
commit 7c27ba0c48
3 changed files with 126 additions and 4 deletions
@@ -40,6 +40,8 @@
const BLOCKED_SYSTEM_SENDERS_STORAGE_KEY = 'chat_blocked_system_senders';
const CHAT_SOUND_MUTED_STORAGE_KEY = 'chat_sound_muted';
const BLOCKABLE_SYSTEM_SENDERS = ['钓鱼播报', '星海小博士', '百家乐', '跑马', '神秘箱子'];
const hoverTooltip = document.getElementById('chat-hover-tooltip');
let activeTooltipTrigger = null;
// ── 消息区:手机端双触发打开用户名片(PC 端靠 ondblclick 内联属性)──
// span[data-u] 由 clickableUser() 生成,touchend 委托至容器避免每条消息单独绑定
@@ -833,6 +835,94 @@
}
}
/**
* 根据鼠标位置摆放即时提示层,避免超出浏览器可视区域。
*
* @param {MouseEvent} event 鼠标事件对象
*/
function positionHoverTooltip(event) {
if (!hoverTooltip) {
return;
}
const offset = 14;
const tooltipWidth = hoverTooltip.offsetWidth;
const tooltipHeight = hoverTooltip.offsetHeight;
const maxLeft = window.innerWidth - tooltipWidth - 8;
const maxTop = window.innerHeight - tooltipHeight - 8;
const nextLeft = Math.min(event.clientX + offset, Math.max(8, maxLeft));
const nextTop = Math.min(event.clientY + offset, Math.max(8, maxTop));
hoverTooltip.style.left = `${nextLeft}px`;
hoverTooltip.style.top = `${nextTop}px`;
}
/**
* 立即显示右侧名单图标提示,替代浏览器原生 title 的延迟行为。
*
* @param {HTMLElement|null} trigger 触发提示的图标元素
* @param {MouseEvent} event 鼠标事件对象
*/
function showHoverTooltip(trigger, event) {
if (!hoverTooltip || !trigger) {
return;
}
const tooltipText = trigger.dataset.instantTooltip || '';
if (!tooltipText) {
return;
}
activeTooltipTrigger = trigger;
hoverTooltip.textContent = tooltipText;
hoverTooltip.style.display = 'block';
positionHoverTooltip(event);
}
/**
* 隐藏右侧名单的即时提示层。
*/
function hideHoverTooltip() {
if (!hoverTooltip) {
return;
}
activeTooltipTrigger = null;
hoverTooltip.style.display = 'none';
hoverTooltip.textContent = '';
}
// 通过事件委托托管动态生成的名单徽章,确保鼠标移入后立刻显示提示。
document.addEventListener('mouseover', (event) => {
const trigger = event.target.closest('[data-instant-tooltip]');
if (!trigger) {
return;
}
showHoverTooltip(trigger, event);
});
document.addEventListener('mousemove', (event) => {
if (!activeTooltipTrigger) {
return;
}
positionHoverTooltip(event);
});
document.addEventListener('mouseout', (event) => {
const trigger = event.target.closest('[data-instant-tooltip]');
if (!trigger || trigger !== activeTooltipTrigger) {
return;
}
if (event.relatedTarget && trigger.contains(event.relatedTarget)) {
return;
}
hideHoverTooltip();
});
// ── 渲染在线人员列表(支持排序) ──────────────────
/**
* 核心渲染函数:将在线用户渲染到指定容器(桌面端名单区和手机端抽屉共用)
@@ -889,14 +979,18 @@
let badges = '';
if (user.position_icon) {
const posTitle = (user.position_name || '在职') + ' · ' + username;
const safePosTitle = escapeHtml(String(posTitle));
const safePositionIcon = escapeHtml(String(user.position_icon || '🎖️'));
badges +=
`<span style="font-size:13px; margin-left:2px;" title="${posTitle}">${user.position_icon}</span>`;
`<span class="user-badge-icon" style="font-size:13px; margin-left:2px;" data-instant-tooltip="${safePosTitle}">${safePositionIcon}</span>`;
} else if (user.is_admin) {
badges += `<span style="font-size:12px; margin-left:2px;" title="最高统帅">🎖️</span>`;
badges += `<span class="user-badge-icon" style="font-size:12px; margin-left:2px;" data-instant-tooltip="最高统帅">🎖️</span>`;
} else if (user.vip_icon) {
const vipColor = user.vip_color || '#f59e0b';
const safeVipTitle = escapeHtml(String(user.vip_name || 'VIP'));
const safeVipIcon = escapeHtml(String(user.vip_icon || '👑'));
badges +=
`<span style="font-size:12px; margin-left:2px; color:${vipColor};" title="${user.vip_name || 'VIP'}">${user.vip_icon}</span>`;
`<span class="user-badge-icon" style="font-size:12px; margin-left:2px; color:${vipColor};" data-instant-tooltip="${safeVipTitle}">${safeVipIcon}</span>`;
}
// 女生名字使用玫粉色