ERP/frontend/js/components/notifications.js

256 lines
8.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

(() => {
let notificationInterval = null;
let isOpen = false;
let isInitialized = false;
// 格式化时间
function formatTime(ts) {
if (!ts) return '';
try {
// 解析ISO格式的时间字符串已经是北京时间
const date = new Date(ts);
const now = new Date();
// 计算时间差(毫秒)
const diff = now - date;
const minutes = Math.floor(diff / 60000);
const hours = Math.floor(diff / 3600000);
const days = Math.floor(diff / 86400000);
if (minutes < 1) return '刚刚';
if (minutes < 60) return `${minutes}分钟前`;
if (hours < 24) return `${hours}小时前`;
if (days < 7) return `${days}天前`;
// 超过7天显示完整日期
return date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit'
});
} catch (e) {
console.error('时间格式化错误:', e, ts);
return ts;
}
}
// 获取操作的中文描述
function getActionText(action) {
const actionMap = {
'批量上传MAC文件': '批量上传了MAC文件',
'批量上传发货记录文件': '批量上传了发货记录',
'添加人员信息': '添加了人员信息',
'上传发货记录': '上传了发货记录',
'上传MAC与批次': '上传了MAC与批次',
'批量上传不良明细文件': '批量上传了不良明细',
'上传返修记录': '上传了返修记录',
'上传良/不良统计': '上传了良/不良统计',
'上传不良明细': '上传了不良明细'
};
return actionMap[action] || action;
}
// 更新未读数量
async function updateUnreadCount() {
try {
const data = await API.getUnreadCount();
const badge = document.getElementById('notification-badge');
const count = data.count || 0;
if (count > 0) {
badge.textContent = count > 99 ? '99+' : count;
badge.style.display = 'block';
} else {
badge.style.display = 'none';
}
} catch (e) {
console.error('获取未读数量失败:', e);
}
}
// 加载通知列表
async function loadNotifications() {
try {
const data = await API.getNotifications();
const list = data.list || [];
const container = document.getElementById('notification-list');
if (list.length === 0) {
container.innerHTML = '<div class="notification-empty">暂无消息通知</div>';
return;
}
container.innerHTML = list.map(item => `
<div class="notification-item ${item.read ? '' : 'unread'}" data-id="${item.id}">
<div class="notification-username">${item.username || '用户'}</div>
<div class="notification-action">${getActionText(item.action)}</div>
${item.detail ? `<div class="notification-detail">${item.detail}</div>` : ''}
<div class="notification-time">${formatTime(item.ts)}</div>
</div>
`).join('');
// 为每个通知项添加点击事件
container.querySelectorAll('.notification-item').forEach(item => {
item.addEventListener('click', async () => {
const id = item.dataset.id;
if (item.classList.contains('unread')) {
try {
await API.markNotificationRead(id);
item.classList.remove('unread');
await updateUnreadCount();
} catch (e) {
console.error('标记已读失败:', e);
}
}
});
});
} catch (e) {
console.error('加载通知失败:', e);
}
}
// 切换通知面板
function togglePanel() {
const panel = document.getElementById('notification-panel');
if (!panel) {
console.error('[Notifications] 找不到面板元素');
return;
}
isOpen = !isOpen;
console.log('[Notifications] 面板状态:', isOpen ? '打开' : '关闭');
if (isOpen) {
panel.style.display = 'flex';
loadNotifications();
} else {
panel.style.display = 'none';
}
}
// 初始化通知系统
async function initNotifications() {
// 防止重复初始化
if (isInitialized) {
console.log('[Notifications] 已经初始化,跳过');
return;
}
try {
// 检查用户角色
const user = await API.me();
if (user.role !== 'superadmin') {
console.log('[Notifications] 非超级管理员,不显示通知');
return; // 只有超级管理员才显示通知铃铛
}
// 显示通知铃铛
const bell = document.getElementById('notification-bell');
if (!bell) {
console.error('[Notifications] 找不到铃铛元素');
return;
}
bell.style.display = 'inline-flex';
console.log('[Notifications] 铃铛已显示');
// 移除旧的事件监听器(如果有)
const newBell = bell.cloneNode(true);
bell.parentNode.replaceChild(newBell, bell);
// 绑定铃铛点击事件
newBell.addEventListener('click', (e) => {
console.log('[Notifications] 铃铛被点击');
e.preventDefault();
e.stopPropagation();
togglePanel();
});
// 绑定全部标记为已读按钮(移除旧的事件监听器)
const markAllBtn = document.getElementById('mark-all-read');
if (markAllBtn) {
const newMarkAllBtn = markAllBtn.cloneNode(true);
markAllBtn.parentNode.replaceChild(newMarkAllBtn, markAllBtn);
newMarkAllBtn.addEventListener('click', async (e) => {
e.stopPropagation();
try {
await API.markAllNotificationsRead();
await loadNotifications();
await updateUnreadCount();
API.toast('已全部标记为已读');
} catch (e) {
console.error('标记全部已读失败:', e);
}
});
}
// 绑定删除已读消息按钮(移除旧的事件监听器)
const deleteBtn = document.getElementById('delete-read');
if (deleteBtn) {
const newDeleteBtn = deleteBtn.cloneNode(true);
deleteBtn.parentNode.replaceChild(newDeleteBtn, deleteBtn);
newDeleteBtn.addEventListener('click', async (e) => {
e.stopPropagation();
if (!confirm('确定要删除所有已读消息吗?')) {
return;
}
try {
const result = await API.deleteReadNotifications();
await loadNotifications();
await updateUnreadCount();
API.toast(`已删除 ${result.count || 0} 条已读消息`);
} catch (e) {
console.error('删除已读消息失败:', e);
}
});
}
// 点击其他地方关闭面板
document.addEventListener('click', (e) => {
const panel = document.getElementById('notification-panel');
const currentBell = document.getElementById('notification-bell');
if (isOpen && panel && currentBell && !panel.contains(e.target) && !currentBell.contains(e.target)) {
isOpen = false;
panel.style.display = 'none';
}
});
// 初始加载未读数量
await updateUnreadCount();
// 每30秒更新一次未读数量
if (notificationInterval) {
clearInterval(notificationInterval);
}
notificationInterval = setInterval(updateUnreadCount, 30000);
isInitialized = true;
console.log('[Notifications] 初始化完成');
} catch (e) {
console.error('初始化通知系统失败:', e);
}
}
// 清理定时器
function cleanupNotifications() {
if (notificationInterval) {
clearInterval(notificationInterval);
notificationInterval = null;
}
isInitialized = false;
isOpen = false;
console.log('[Notifications] 已清理');
}
// 导出到全局
window.NotificationSystem = {
init: initNotifications,
cleanup: cleanupNotifications,
refresh: updateUnreadCount
};
})();