import db from './sqlite'; interface TelegramNotificationConfig { id: number; name: string; botToken: string; chatId: string; notificationTypes: string[]; isEnabled: boolean; } interface TransactionNotificationData { id: number; type: string; amount: number; currency: string; categoryName?: string; accountName?: string; transactionDate: string; description?: string; status: string; } /** * 获取所有启用的Telegram通知配置 */ export function getEnabledNotificationConfigs( notificationType: string = 'transaction', ): TelegramNotificationConfig[] { const rows = db .prepare<{ id: number; name: string; bot_token: string; chat_id: string; notification_types: string; is_enabled: number }>( ` SELECT id, name, bot_token, chat_id, notification_types, is_enabled FROM telegram_notification_configs WHERE is_enabled = 1 `, ) .all(); return rows .map((row) => ({ id: row.id, name: row.name, botToken: row.bot_token, chatId: row.chat_id, notificationTypes: JSON.parse(row.notification_types) as string[], isEnabled: row.is_enabled === 1, })) .filter((config) => config.notificationTypes.includes(notificationType)); } /** * 格式化交易金额 */ function formatAmount(amount: number, currency: string): string { const formatted = amount.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2, }); return `${currency} ${formatted}`; } /** * 格式化交易类型 */ function formatTransactionType(type: string): string { const typeMap: Record = { income: '💰 收入', expense: '💸 支出', transfer: '🔄 转账', }; return typeMap[type] || type; } /** * 格式化交易状态 */ function formatTransactionStatus(status: string): string { const statusMap: Record = { draft: '📝 草稿', pending: '⏳ 待审核', approved: '✅ 已批准', rejected: '❌ 已拒绝', paid: '💵 已支付', }; return statusMap[status] || status; } /** * 构建交易通知消息 */ function buildTransactionMessage( transaction: TransactionNotificationData, action: string = 'created', ): string { const actionMap: Record = { created: '📋 新增账目记录', updated: '✏️ 更新账目记录', deleted: '🗑️ 删除账目记录', }; const lines: string[] = [ `${actionMap[action] || '📋 账目记录'}`, '', `类型:${formatTransactionType(transaction.type)}`, `金额:${formatAmount(transaction.amount, transaction.currency)}`, `日期:${transaction.transactionDate}`, ]; if (transaction.categoryName) { lines.push(`分类:${transaction.categoryName}`); } if (transaction.accountName) { lines.push(`账户:${transaction.accountName}`); } lines.push(`状态:${formatTransactionStatus(transaction.status)}`); if (transaction.description) { lines.push(``, `备注:${transaction.description}`); } lines.push( ``, `🕐 记录时间:${new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' })}`, ); return lines.join('\n'); } /** * 发送Telegram消息 */ async function sendTelegramMessage( botToken: string, chatId: string, message: string, ): Promise { try { const url = `https://api.telegram.org/bot${botToken}/sendMessage`; const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ chat_id: chatId, text: message, parse_mode: 'HTML', }), }); if (!response.ok) { const error = await response.json().catch(() => ({})); console.error( '[telegram-bot] Failed to send message:', response.status, error, ); return false; } return true; } catch (error) { console.error('[telegram-bot] Error sending message:', error); return false; } } /** * 通知交易记录 */ export async function notifyTransaction( transaction: TransactionNotificationData, action: string = 'created', ): Promise { const configs = getEnabledNotificationConfigs('transaction'); if (configs.length === 0) { console.log('[telegram-bot] No enabled notification configs found'); return; } const message = buildTransactionMessage(transaction, action); const results = await Promise.allSettled( configs.map((config) => sendTelegramMessage(config.botToken, config.chatId, message), ), ); results.forEach((result, index) => { if (result.status === 'fulfilled' && result.value) { console.log( `[telegram-bot] Sent notification via config: ${configs[index].name}`, ); } else { console.error( `[telegram-bot] Failed to send notification via config: ${configs[index].name}`, ); } }); } /** * 测试Telegram Bot配置 */ export async function testTelegramConfig( botToken: string, chatId: string, ): Promise<{ success: boolean; error?: string }> { try { const testMessage = `🤖 KT财务系统\n\n✅ Telegram通知配置测试成功!\n\n🕐 ${new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' })}`; const success = await sendTelegramMessage(botToken, chatId, testMessage); if (success) { return { success: true }; } else { return { success: false, error: '发送消息失败,请检查Bot Token和Chat ID' }; } } catch (error: unknown) { return { success: false, error: error instanceof Error ? error.message : '未知错误', }; } }