logo NodeSeekbeta

想看大家的komari通知模版。

想看大家的komari通知模版,好看的主题贴不少。

可以看看你们的通知模版吗?

1234
  • @solaireh3 #5

    // 提取公共常量到顶层,避免作用域找不到
    const TG_TOKEN = "获取到的Telegram Bot Token";
    const TG_CHAT_ID = "你的Telegram Chat ID"; // 可以是个人或群组的ID
    const MONITOR_URL = '你的地址'; // 监控系统主页链接
    
    // 公共工具函数提取到顶层,所有async函数都能访问
    /**
     * 统一转换时间为 UTC+8 格式化字符串
     * @param {string|Date|null} timeStr 原始时间
     * @returns {string} 格式化后 UTC+8 时间文本
     */
    function ensureUTC8Time(timeStr) {
      if (!timeStr) {
        // 无时间时使用当前UTC+8时间
        const now = new Date();
        // 本地时间 + 时区偏移抹平 +8小时
        const utc8Time = new Date(now.getTime() + (8 * 60 * 60 * 1000) - (now.getTimezoneOffset() * 60 * 1000));
        return utc8Time.toISOString().replace('Z', '+08:00');
      }
    
      // 解析时间并转换为UTC+8
      const date = new Date(timeStr);
      // 检查是否为有效日期
      if (isNaN(date.getTime())) {
        console.warn(`无效的时间格式: ${timeStr},使用当前UTC+8时间`);
        const now = new Date();
        const utc8Time = new Date(now.getTime() + (8 * 60 * 60 * 1000) - (now.getTimezoneOffset() * 60 * 1000));
        return utc8Time.toISOString().replace('Z', '+08:00');
      }
    
      // 转换为UTC+8时间字符串
      const utcTimestamp = date.getTime() - (date.getTimezoneOffset() * 60 * 1000);
      const utc8Timestamp = utcTimestamp + (8 * 60 * 60 * 1000);
      const utc8Date = new Date(utc8Timestamp);
    
      // 格式化输出
      const year = utc8Date.getUTCFullYear();
      const month = String(utc8Date.getUTCMonth() + 1).padStart(2, '0');
      const day = String(utc8Date.getUTCDate()).padStart(2, '0');
      const hours = String(utc8Date.getUTCHours()).padStart(2, '0');
      const minutes = String(utc8Date.getUTCMinutes()).padStart(2, '0');
      const seconds = String(utc8Date.getUTCSeconds()).padStart(2, '0');
    
      return `${year}-${month}-${day} ${hours}:${minutes}:${seconds} (UTC+8)`;
    }
    
    /**
     * 格式化字节大小
     * @param {number} bytes
     * @returns {string}
     */
    function formatBytes(bytes) {
      if (bytes === 0) return '0 B';
      const k = 1024;
      const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
      const i = Math.floor(Math.log(bytes) / Math.log(k));
      return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
    }
    
    /**
     * 格式化到期时间并计算剩余天数
     * @param {string} expireTimeStr
     * @returns {string}
     */
    function formatExpireTime(expireTimeStr) {
      if (!expireTimeStr) return '永久有效';
    
      const expireDate = new Date(expireTimeStr);
      if (isNaN(expireDate.getTime())) return '时间格式错误';
    
      const now = new Date();
      const nowUTC8 = new Date(now.getTime() + (8 * 60 * 60 * 1000) - (now.getTimezoneOffset() * 60 * 1000));
      const expireUTC8 = new Date(expireDate.getTime() + (8 * 60 * 60 * 1000) - (expireDate.getTimezoneOffset() * 60 * 1000));
    
      const diffDays = Math.ceil((expireUTC8 - nowUTC8) / (1000 * 60 * 60 * 24));
    
      const y = expireUTC8.getUTCFullYear();
      const m = String(expireUTC8.getUTCMonth() + 1).padStart(2, '0');
      const d = String(expireUTC8.getUTCDate()).padStart(2, '0');
      const dateStr = `${y}-${m}-${d}`;
    
      if (diffDays < 0) return `已过期 (${dateStr})`;
      if (diffDays === 0) return `今日到期 (${dateStr})`;
      if (diffDays <= 7) return `即将到期(${diffDays}天后) ${dateStr}`;
      return `${dateStr} (剩余${diffDays}天)`;
    }
    
    /**
     * 获取事件类型图标描述
     * @param {string} eventType
     * @returns {string}
     */
    function getEventTypeDesc(eventType) {
      const eventMap = {
        'Offline': '❌ 服务器离线',
        'Online': '✅ 服务器上线',
        'Alert': '⚠️ 监控告警',
        'Renew': '⏰ 服务器已自动续费',
        'Expire': '🚨 服务到期提醒',
        'Test': '🧪 测试通知',
        'offline': '❌ 服务器离线'
      };
      return eventMap[eventType] || `📊 ${eventType}`;
    }
    
    /**
     * 生成单台服务器信息卡片文本
     * @param {object} client
     * @param {number} index
     * @returns {string}
     */
    function generateClientCard(client, index) {
      let card = `\n┌── 🖥️ ${index}. <b>${client.name || '未知服务器'}</b>`;
      card += `\n│  📍 地域: ${client.region || '未设置'}`;
      card += `\n│  🖼️ 虚拟化: ${client.virtualization || '未知'} | 架构: ${client.arch || '未知'}`;
      card += `\n│  🧮 CPU: ${client.cpu_name || '未知'} (${client.cpu_cores || 0}核)`;
      card += `\n│  📦 配置: 内存 ${formatBytes(client.mem_total || 0)} | 磁盘 ${formatBytes(client.disk_total || 0)}`;
    
      let ips = [];
      if (client.ipv4) ips.push(`IPv4: ${client.ipv4}`);
      if (client.ipv6) ips.push(`IPv6: ${client.ipv6}`);
      card += `\n│  🌐 ${ips.length > 0 ? ips.join(' | ') : '无公网IP'}`;
    
      card += `\n│  📋 系统: ${client.os || '未知'} (内核: ${client.kernel_version || '未知'})`;
    
      if (client.price) {
        const renewal = client.auto_renewal ? '✅ 自动续费' : '❌ 手动续费';
        if (client.price == -1) {
          card += `\n│  💰 价格: 免费 | 周期: ${client.billing_cycle || '月'}`;
        } else {
          card += `\n│  💰 价格: ${client.currency || '$'}${client.price} | 周期: ${client.billing_cycle || '月'}`;
        }
        card += `\n│  📅 到期: ${formatExpireTime(client.expired_at)} | ${renewal}`;
      }
    
      if (client.tags) card += `\n│  🏷️ 标签: ${client.tags.replace(';', ' | ')}`;
      if (client.remark) card += `\n│  📝 备注: ${client.remark.substring(0, 50)}${client.remark.length > 50 ? '...' : ''}`;
    
      card += `\n└── 🆔 UUID: ${client.uuid || '未设置'}`;
      return card;
    }
    
    async function sendMessage(message, title, buttons = []) {
      const url = `https://api.telegram.org/bot${TG_TOKEN}/sendMessage`;
    
      const requestBody = {
        chat_id: TG_CHAT_ID,
        text: `<b>${title}</b>\n\n${message}`,
        parse_mode: 'HTML',
        disable_web_page_preview: true
      };
    
      if (buttons.length > 0) {
        requestBody.reply_markup = {
          inline_keyboard: buttons,
          resize_keyboard: true,
          one_time_keyboard: false
        };
      }
    
      const resp = await fetch(url, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(requestBody),
      });
    
      if (!resp.ok) {
        console.error('Failed to send message:', resp.status, resp.statusText);
        return false;
      }
      return true;
    }
    
    async function sendEvent(event) {
      try {
        const title = `${getEventTypeDesc(event.event) || 'ℹ️'} Komari 通知`;
        let message = '';
    
        message += `📅 <b>事件时间 (UTC+8)</b>: ${ensureUTC8Time(event.time)}\n`;
        message += `📢 <b>事件类型</b>: ${event.event || '未知'}\n`;
        if (event.emoji) message += `🔤 <b>标识</b>: ${event.emoji}\n`;
        if (event.message && event.message.trim()) {
          message += `📝 <b>事件说明</b>: ${event.message}\n`;
        }
        message += '\n' + '━'.repeat(20) + '\n';
    
        const buttons = [];
        buttons.push([{
          text: '🔍 监控主页',
          url: `${MONITOR_URL}/`
        }]);
    
        if (event.clients && event.clients.length > 0) {
          const totalClients = event.clients.length;
          message += `🖥️ <b>受影响服务器</b>: ${totalClients} 台\n\n`;
    
          const displayCount = Math.min(totalClients, 3);
          const clientButtons = [];
    
          for (let i = 0; i < displayCount; i++) {
            const client = event.clients[i];
            message += generateClientCard(client, i + 1);
    
            if (client.uuid) {
              clientButtons.push({
                text: `${i + 1}. ${client.name || '服务器详情'}`,
                url: `${MONITOR_URL}/instance/${client.uuid}`
              });
            }
          }
    
          if (clientButtons.length > 0) {
            buttons.push(clientButtons);
          }
    
          if (totalClients > 3) {
            message += `\n\n📌 仅展示前3台,剩余 ${totalClients - 3} 台请查看监控系统`;
            buttons.push([{
              text: `📑 查看全部${totalClients}台机器`,
              url: `${MONITOR_URL}/`
            }]);
          }
        } else {
          message += '🖥️ <b>受影响服务器</b>: 无关联服务器信息\n';
        }
    
        const success = await sendMessage(message, title, buttons);
        if (success) {
          console.log(`事件通知已发送: ${event.event}`);
        } else {
          console.error(`事件通知发送失败: ${event.event}`);
        }
        return success;
    
      } catch (error) {
        console.error('发送事件通知时出错:', error);
    
        const fallbackMessage = `${event.emoji || ''} <b>${event.event || '未知事件'}</b>
    📅 时间 (UTC+8): ${ensureUTC8Time(event.time || new Date())}
    📝 说明: ${event.message || '无详细信息'}
    🖥️ 受影响服务器: ${event.clients?.length || 0} 台`;
    
        const fallbackTitle = '⚠️ Komari 通知 - 异常';
        const fallbackButtons = [[{
          text: '🔍 监控主页',
          url: `${MONITOR_URL}/`
        }]];
    
        try {
          return await sendMessage(fallbackMessage, fallbackTitle, fallbackButtons);
        } catch (fallbackError) {
          console.error('备用通知也失败:', fallbackError);
          return false;
        }
      }
    }
    
  • {{emoji}}
    事件: {{event}}
    服务: {{client}}
    消息: {{message}}
    时间: {{time}}

  • @Amity #15 太阳边上鼠标放上去找找

  • @Amity #19 网站后面加个/admin 就行了

  • 未启用

  • @LIN-2077 #1 发布于2026/6/21 10:44:01
    未启用
    好奔放🤣

  • image

  • 默认就好S60621-10490278_com.tencent.mobileqq

  • 来早了,一会儿再来看评论

  • @smagic #7 发布于2026/6/21 10:51:37
    @solaireh3 #5

    async function sendMessage(message, title, buttons = []) {
      const token = "你的bot token"
      const chatId = "你的chat_id"
    
    
      const url = `https://api.telegram.org/bot${token}/sendMessage`;
      
      // 构建请求体
      const requestBody = {
        chat_id: chatId,
        text: `<b>${title}</b>\n\n${message}`,
        parse_mode: 'HTML',
        disable_web_page_preview: true // 禁用链接预览,让消息更整洁
      };
    
      // 如果有按钮,添加键盘配置
      if (buttons.length > 0) {
        requestBody.reply_markup = {
          inline_keyboard: buttons,
          resize_keyboard: true,
          one_time_keyboard: false
        };
      }
    
      const resp = await fetch(url, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(requestBody),
      });
    
      if (!resp.ok) {
        console.error('Failed to send message:', resp.status, resp.statusText);
        return false;
      }
      return true;
    }
    
    async function sendEvent(event) {
      try {
        // 时区检查和处理函数 - 确保时间始终为UTC+8
        const ensureUTC8Time = (timeStr) => {
          if (!timeStr) {
            // 无时间时使用当前UTC+8时间
            const now = new Date();
            const utc8Time = new Date(now.getTime() + (8 * 60 * 60 * 1000) - (now.getTimezoneOffset() * 60 * 1000));
            return utc8Time.toISOString().replace('Z', '+08:00');
          }
          
          // 解析时间并转换为UTC+8
          const date = new Date(timeStr);
          // 检查是否为有效日期
          if (isNaN(date.getTime())) {
            console.warn(`无效的时间格式: ${timeStr},使用当前UTC+8时间`);
            const now = new Date();
            const utc8Time = new Date(now.getTime() + (8 * 60 * 60 * 1000) - (now.getTimezoneOffset() * 60 * 1000));
            return utc8Time.toISOString().replace('Z', '+08:00');
          }
          
          // 转换为UTC+8时间字符串(保留原始格式,仅确保时区正确)
          // 获取UTC时间戳,加上8小时偏移
          const utcTimestamp = date.getTime() - (date.getTimezoneOffset() * 60 * 1000);
          const utc8Timestamp = utcTimestamp + (8 * 60 * 60 * 1000);
          const utc8Date = new Date(utc8Timestamp);
          
          // 格式化输出为 ISO 格式,明确标注UTC+8
          const year = utc8Date.getUTCFullYear();
          const month = String(utc8Date.getUTCMonth() + 1).padStart(2, '0');
          const day = String(utc8Date.getUTCDate()).padStart(2, '0');
          const hours = String(utc8Date.getUTCHours()).padStart(2, '0');
          const minutes = String(utc8Date.getUTCMinutes()).padStart(2, '0');
          const seconds = String(utc8Date.getUTCSeconds()).padStart(2, '0');
          
          return `${year}-${month}-${day} ${hours}:${minutes}:${seconds} (UTC+8)`;
        };
    
        // 格式化文件大小
        const formatBytes = (bytes) => {
          if (bytes === 0) return '0 B';
          const k = 1024;
          const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
          const i = Math.floor(Math.log(bytes) / Math.log(k));
          return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
        };
    
        // 格式化到期时间(确保使用UTC+8)
        const formatExpireTime = (expireTimeStr) => {
          if (!expireTimeStr) return '永久有效';
          
          // 确保到期时间也使用UTC+8
          const expireDate = new Date(expireTimeStr);
          if (isNaN(expireDate.getTime())) return '时间格式错误';
          
          const now = new Date();
          const nowUTC8 = new Date(now.getTime() + (8 * 60 * 60 * 1000) - (now.getTimezoneOffset() * 60 * 1000));
          const expireUTC8 = new Date(expireDate.getTime() + (8 * 60 * 60 * 1000) - (expireDate.getTimezoneOffset() * 60 * 1000));
          
          const diffDays = Math.ceil((expireUTC8 - nowUTC8) / (1000 * 60 * 60 * 24));
          
          if (diffDays < 0) return `已过期 (${expireUTC8.getUTCFullYear()}-${String(expireUTC8.getUTCMonth()+1).padStart(2,'0')}-${String(expireUTC8.getUTCDate()).padStart(2,'0')})`;
          if (diffDays === 0) return `今日到期 (${expireUTC8.getUTCFullYear()}-${String(expireUTC8.getUTCMonth()+1).padStart(2,'0')}-${String(expireUTC8.getUTCDate()).padStart(2,'0')})`;
          if (diffDays <= 7) return `即将到期(${diffDays}天后) ${expireUTC8.getUTCFullYear()}-${String(expireUTC8.getUTCMonth()+1).padStart(2,'0')}-${String(expireUTC8.getUTCDate()).padStart(2,'0')}`;
          return `${expireUTC8.getUTCFullYear()}-${String(expireUTC8.getUTCMonth()+1).padStart(2,'0')}-${String(expireUTC8.getUTCDate()).padStart(2,'0')} (剩余${diffDays}天)`;
        };
    
        // 获取事件类型描述
        const getEventTypeDesc = (eventType) => {
          const eventMap = {
            'Offline': '❌ 服务器离线',
            'Online': '✅ 服务器上线',
            'Alert': '⚠️ 监控告警',
            'Renew': '⏰ 服务器已自动续费',
            'Expire': '🚨 服务到期提醒',
            'Test': '🧪 测试通知',
            'offline': '❌ 服务器离线' // 兼容小写的offline
          };
          return eventMap[eventType] || `📊 ${eventType}`;
        };
    
        // 生成详细的服务器信息卡片
        const generateClientCard = (client, index) => {
          let card = `\n┌── 🖥️ ${index}. <b>${client.name || '未知服务器'}</b>`;
          card += `\n│  📍 地域: ${client.region || '未设置'}`;
          card += `\n│  🖼️ 虚拟化: ${client.virtualization || '未知'} | 架构: ${client.arch || '未知'}`;
          card += `\n│  🧮 CPU: ${client.cpu_name || '未知'} (${client.cpu_cores || 0}核)`;
          card += `\n│  📦 配置: 内存 ${formatBytes(client.mem_total || 0)} | 磁盘 ${formatBytes(client.disk_total || 0)}`;
          
          // IP信息
          let ips = [];
          if (client.ipv4) ips.push(`IPv4: ${client.ipv4}`);
          if (client.ipv6) ips.push(`IPv6: ${client.ipv6}`);
          card += `\n│  🌐 ${ips.length > 0 ? ips.join(' | ') : '无公网IP'}`;
          
          // 系统信息
          card += `\n│  📋 系统: ${client.os || '未知'} (内核: ${client.kernel_version || '未知'})`;
          
          // 计费信息
          if (client.price) {
            const renewal = client.auto_renewal ? '✅ 自动续费' : '❌ 手动续费';
            if(client.price == -1){
              card += `\n│  💰 价格: 免费 | 周期: ${client.billing_cycle || '月'}`;
            }else{
              card += `\n│  💰 价格: ${client.currency || '$'}${client.price} | 周期: ${client.billing_cycle || '月'}`;
            }
            card += `\n│  📅 到期: ${formatExpireTime(client.expired_at)} | ${renewal}`;
          }
          
          // 标签和备注
          if (client.tags) card += `\n│  🏷️ 标签: ${client.tags.replace(';', ' | ')}`;
          if (client.remark) card += `\n│  📝 备注: ${client.remark.substring(0, 50)}${client.remark.length > 50 ? '...' : ''}`;
          
          card += `\n└── 🆔 UUID: ${client.uuid || '未设置'}`;
          
          return card;
        };
    
        const title = `${getEventTypeDesc(event.event) || 'ℹ️'} Komari 通知`;
        let message = '';
    
        // 头部信息 - 使用UTC+8时间
        message += `📅 <b>事件时间 (UTC+8)</b>: ${ensureUTC8Time(event.time)}\n`;
        message += `📢 <b>事件类型</b>: ${event.event || '未知'}\n`;
        if (event.emoji) message += `🔤 <b>标识</b>: ${event.emoji}\n`;
        if (event.message && event.message.trim()) {
          message += `📝 <b>事件说明</b>: ${event.message}\n`;
        }
        message += '\n' + '━'.repeat(20) + '\n';
    
        // 构建按钮数组
        const buttons = [];
        // 始终添加监控主页按钮(第一行)
        buttons.push([{
          text: '🔍 监控主页',
          url: 'https://monitor.smagical.de/'
        }]);
    
        if (event.clients && event.clients.length > 0) {
          const totalClients = event.clients.length;
          message += `🖥️ <b>受影响服务器</b>: ${totalClients} 台\n\n`;
          
          // 只展示前三台机器
          const displayCount = Math.min(totalClients, 3);
          const clientButtons = [];
          
          for (let i = 0; i < displayCount; i++) {
            const client = event.clients[i];
            message += generateClientCard(client, i + 1);
            
            // 为每台机器添加详情按钮
            if (client.uuid) {
              clientButtons.push({
                text: `${i + 1}. ${client.name || '服务器详情'}`,
                url: `https://monitor.smagical.de/instance/${client.uuid}`
              });
            }
          }
          
          // 添加机器详情按钮行
          if (clientButtons.length > 0) {
            buttons.push(clientButtons);
          }
          
          // 超过3台时添加查看更多按钮
          if (totalClients > 3) {
            message += `\n\n📌 仅展示前3台,剩余 ${totalClients - 3} 台请查看监控系统`;
            buttons.push([{
              text: `📑 查看全部${totalClients}台机器`,
              url: 'https://monitor.smagical.de/'
            }]);
          }
        } else {
          message += '🖥️ <b>受影响服务器</b>: 无关联服务器信息\n';
        }
        
        // 发送通知(传入按钮配置)
        const success = await sendMessage(message, title, buttons);
        if (success) {
          console.log(`事件通知已发送: ${event.event}`);
        } else {
          console.error(`事件通知发送失败: ${event.event}`);
        }
        return success;
        
      } catch (error) {
        console.error('发送事件通知时出错:', error);
        
        // 发送简化的错误通知(也包含基础监控按钮)
        const fallbackMessage = `${event.emoji || ''} <b>${event.event || '未知事件'}</b>
    📅 时间 (UTC+8): ${ensureUTC8Time(event.time || new Date())}
    📝 说明: ${event.message || '无详细信息'}
    🖥️ 受影响服务器: ${event.clients?.length || 0} 台`;
        
        const fallbackTitle = '⚠️ Komari 通知 - 异常';
        const fallbackButtons = [[{
          text: '🔍 监控主页',
          url: 'https://monitor.smagical.de/'
        }]];
        
        try {
          return await sendMessage(fallbackMessage, fallbackTitle, fallbackButtons);
        } catch (fallbackError) {
          console.error('备用通知也失败:', fallbackError);
          return false;
        }
      }
    }
    

    谢谢老板

1234

你好啊,陌生人!

我的朋友,看起来你是新来的,如果想参与到讨论中,点击下面的按钮!

📈用户数目📈

目前论坛共有62049位seeker

🎉欢迎新用户🎉