|
@@ -5,11 +5,31 @@ const path = require('path');
|
|
const TelegramBot = require('node-telegram-bot-api');
|
|
const TelegramBot = require('node-telegram-bot-api');
|
|
const fs = require('fs');
|
|
const fs = require('fs');
|
|
const moment = require('moment');
|
|
const moment = require('moment');
|
|
-const { pool, testConnection } = require('./config/database');
|
|
|
|
|
|
+const {
|
|
|
|
+ pool,
|
|
|
|
+ testConnection
|
|
|
|
+} = require('./config/database');
|
|
const initDatabase = require('./config/initDb');
|
|
const initDatabase = require('./config/initDb');
|
|
const Group = require('./models/Group');
|
|
const Group = require('./models/Group');
|
|
const Transaction = require('./models/Transaction');
|
|
const Transaction = require('./models/Transaction');
|
|
|
|
|
|
|
|
+// 日志格式化函数
|
|
|
|
+function formatLog(data) {
|
|
|
|
+ const separator = '-'.repeat(30);
|
|
|
|
+ let logMessage = `${separator}\n`;
|
|
|
|
+
|
|
|
|
+ if (typeof data === 'object') {
|
|
|
|
+ logMessage += Object.entries(data)
|
|
|
|
+ .map(([key, value]) => `${key}: ${value}`)
|
|
|
|
+ .join('\n');
|
|
|
|
+ } else {
|
|
|
|
+ logMessage += data;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ logMessage += `\n${separator}\n`;
|
|
|
|
+ return logMessage;
|
|
|
|
+}
|
|
|
|
+
|
|
const app = express();
|
|
const app = express();
|
|
|
|
|
|
// 初始化数据存储
|
|
// 初始化数据存储
|
|
@@ -17,11 +37,13 @@ let data = {
|
|
deposits: [], // 入款记录
|
|
deposits: [], // 入款记录
|
|
withdrawals: [], // 下发记录
|
|
withdrawals: [], // 下发记录
|
|
lastUpdate: null,
|
|
lastUpdate: null,
|
|
- allowedGroups: ['4754375683'] // 允许使用的群组ID
|
|
|
|
|
|
+ allowedGroups: [] // 允许使用的群组ID
|
|
};
|
|
};
|
|
|
|
|
|
// 创建机器人实例
|
|
// 创建机器人实例
|
|
-const bot = new TelegramBot(process.env.BOT_TOKEN, { polling: true });
|
|
|
|
|
|
+const bot = new TelegramBot(process.env.BOT_TOKEN, {
|
|
|
|
+ polling: true
|
|
|
|
+});
|
|
|
|
|
|
// 中间件
|
|
// 中间件
|
|
app.use(cors());
|
|
app.use(cors());
|
|
@@ -42,8 +64,8 @@ app.use('/api/settings', require('./routes/settingsRoutes'));
|
|
// 检查群组权限
|
|
// 检查群组权限
|
|
function isGroupAllowed(chatId) {
|
|
function isGroupAllowed(chatId) {
|
|
const chatIdStr = chatId.toString();
|
|
const chatIdStr = chatId.toString();
|
|
- return data.allowedGroups.includes(chatIdStr) ||
|
|
|
|
- data.allowedGroups.includes(chatIdStr.replace('-', ''));
|
|
|
|
|
|
+ return data.allowedGroups.includes(chatIdStr) ||
|
|
|
|
+ data.allowedGroups.includes(chatIdStr.replace('-', ''));
|
|
}
|
|
}
|
|
|
|
|
|
// 检查是否是管理员
|
|
// 检查是否是管理员
|
|
@@ -59,11 +81,16 @@ async function sendMessage(chatId, text, options = {}) {
|
|
const keyboard = generateInlineKeyboard(chatId);
|
|
const keyboard = generateInlineKeyboard(chatId);
|
|
if (!keyboard) {
|
|
if (!keyboard) {
|
|
// 如果键盘无效,发送不带键盘的消息
|
|
// 如果键盘无效,发送不带键盘的消息
|
|
- return await bot.sendMessage(chatId, text, { parse_mode: 'HTML' });
|
|
|
|
|
|
+ return await bot.sendMessage(chatId, text, {
|
|
|
|
+ parse_mode: 'HTML'
|
|
|
|
+ });
|
|
}
|
|
}
|
|
options.reply_markup = keyboard;
|
|
options.reply_markup = keyboard;
|
|
}
|
|
}
|
|
- return await bot.sendMessage(chatId, text, { ...options, parse_mode: 'HTML' });
|
|
|
|
|
|
+ return await bot.sendMessage(chatId, text, {
|
|
|
|
+ ...options,
|
|
|
|
+ parse_mode: 'HTML'
|
|
|
|
+ });
|
|
} catch (error) {
|
|
} catch (error) {
|
|
console.error('发送消息失败:', error);
|
|
console.error('发送消息失败:', error);
|
|
if (error.message.includes('bot was kicked from the group chat')) {
|
|
if (error.message.includes('bot was kicked from the group chat')) {
|
|
@@ -154,18 +181,15 @@ bot.on('message', async (msg) => {
|
|
bot.on('new_chat_members', async (msg) => {
|
|
bot.on('new_chat_members', async (msg) => {
|
|
const chatId = msg.chat.id;
|
|
const chatId = msg.chat.id;
|
|
const newMembers = msg.new_chat_members;
|
|
const newMembers = msg.new_chat_members;
|
|
-
|
|
|
|
|
|
+
|
|
for (const member of newMembers) {
|
|
for (const member of newMembers) {
|
|
if (member.id === (await bot.getMe()).id) {
|
|
if (member.id === (await bot.getMe()).id) {
|
|
- // 机器人被添加到群组
|
|
|
|
- console.log(`机器人被添加到群组: ${chatId}`);
|
|
|
|
-
|
|
|
|
// 检查群组是否在允许列表中
|
|
// 检查群组是否在允许列表中
|
|
const chatIdStr = chatId.toString();
|
|
const chatIdStr = chatId.toString();
|
|
try {
|
|
try {
|
|
// 先检查数据库中是否存在该群组
|
|
// 先检查数据库中是否存在该群组
|
|
const existingGroup = await Group.findByGroupId(chatIdStr);
|
|
const existingGroup = await Group.findByGroupId(chatIdStr);
|
|
-
|
|
|
|
|
|
+
|
|
if (existingGroup) {
|
|
if (existingGroup) {
|
|
// 如果群组存在,更新群组状态为活跃,同时更新群组名称和加入时间
|
|
// 如果群组存在,更新群组状态为活跃,同时更新群组名称和加入时间
|
|
await pool.query(`
|
|
await pool.query(`
|
|
@@ -181,6 +205,13 @@ bot.on('new_chat_members', async (msg) => {
|
|
data.allowedGroups.push(chatIdStr);
|
|
data.allowedGroups.push(chatIdStr);
|
|
saveData();
|
|
saveData();
|
|
}
|
|
}
|
|
|
|
+ // console.log(formatLog({
|
|
|
|
+ // ID: chatIdStr,
|
|
|
|
+ // 名称: msg.chat.title || existingGroup.group_name,
|
|
|
|
+ // 类型: msg.chat.type,
|
|
|
|
+ // 状态: '重新激活',
|
|
|
|
+ // 更新时间: new Date().toLocaleString()
|
|
|
|
+ // }));
|
|
// 发送欢迎消息并显示当前账单
|
|
// 发送欢迎消息并显示当前账单
|
|
await sendMessage(chatId, '感谢重新添加我为群组成员!');
|
|
await sendMessage(chatId, '感谢重新添加我为群组成员!');
|
|
const billMessage = await generateBillMessage(chatId);
|
|
const billMessage = await generateBillMessage(chatId);
|
|
@@ -190,42 +221,149 @@ bot.on('new_chat_members', async (msg) => {
|
|
});
|
|
});
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
|
|
+ // 如果是新群组,打印被添加到新群组的信息
|
|
|
|
+ console.log(formatLog({
|
|
|
|
+ ID: chatId,
|
|
|
|
+ 名称: msg.chat.title || '未命名群组',
|
|
|
|
+ 类型: msg.chat.type,
|
|
|
|
+ 描述: msg.chat.description || '无',
|
|
|
|
+ '添加者信息': {
|
|
|
|
+ ID: msg.from.id,
|
|
|
|
+ 用户名: msg.from.username || '无',
|
|
|
|
+ 姓名: msg.from.first_name,
|
|
|
|
+ ...(msg.from.last_name && {
|
|
|
|
+ 姓: msg.from.last_name
|
|
|
|
+ })
|
|
|
|
+ },
|
|
|
|
+ 添加时间: new Date().toLocaleString()
|
|
|
|
+ }));
|
|
|
|
+
|
|
// 如果群组不存在,创建新群组
|
|
// 如果群组不存在,创建新群组
|
|
const groupData = {
|
|
const groupData = {
|
|
groupId: chatIdStr,
|
|
groupId: chatIdStr,
|
|
groupName: msg.chat.title || '未命名群组',
|
|
groupName: msg.chat.title || '未命名群组',
|
|
- groupType: msg.chat.type === 'private' ? 'personal' : 'public',
|
|
|
|
|
|
+ groupType: msg.chat.type === 'private' ? 'personal' : msg.chat.type,
|
|
creatorId: msg.from.id.toString()
|
|
creatorId: msg.from.id.toString()
|
|
};
|
|
};
|
|
-
|
|
|
|
- const id = await Group.create({
|
|
|
|
- groupId: groupData.groupId,
|
|
|
|
- groupName: groupData.groupName,
|
|
|
|
- creatorId: groupData.creatorId
|
|
|
|
- });
|
|
|
|
- const group = await Group.findById(id);
|
|
|
|
-
|
|
|
|
- if (group) {
|
|
|
|
|
|
+
|
|
|
|
+ console.log(formatLog(groupData));
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ // 直接使用 SQL 插入群组数据
|
|
|
|
+ const [result] = await pool.query(`
|
|
|
|
+ INSERT INTO groups
|
|
|
|
+ (group_id, group_name, group_type, creator_id, is_active, last_join_time)
|
|
|
|
+ VALUES (?, ?, ?, ?, true, CURRENT_TIMESTAMP)
|
|
|
|
+ `, [
|
|
|
|
+ groupData.groupId,
|
|
|
|
+ groupData.groupName,
|
|
|
|
+ groupData.groupType,
|
|
|
|
+ groupData.creatorId
|
|
|
|
+ ]);
|
|
|
|
+
|
|
|
|
+ console.log(formatLog(result));
|
|
|
|
+
|
|
// 更新内存中的群组列表
|
|
// 更新内存中的群组列表
|
|
- data.allowedGroups.push(chatIdStr);
|
|
|
|
- saveData();
|
|
|
|
- await sendMessage(chatId, '感谢添加我为群组成员!使用 /help 查看可用命令。');
|
|
|
|
- } else {
|
|
|
|
- await sendMessage(chatId, '添加群组失败,请联系管理员。');
|
|
|
|
|
|
+ if (!data.allowedGroups.includes(chatIdStr)) {
|
|
|
|
+ data.allowedGroups.push(chatIdStr);
|
|
|
|
+ saveData();
|
|
|
|
+ console.log(formatLog({
|
|
|
|
+ ID: chatIdStr,
|
|
|
|
+ 名称: groupData.groupName,
|
|
|
|
+ 类型: groupData.groupType,
|
|
|
|
+ 状态: '已启用',
|
|
|
|
+ 添加时间: new Date().toLocaleString(),
|
|
|
|
+ 操作者: msg.from.username || msg.from.first_name + ' (' + msg.from.id + ')'
|
|
|
|
+ }));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ console.log(formatLog({
|
|
|
|
+ ID: chatIdStr,
|
|
|
|
+ 名称: groupData.groupName,
|
|
|
|
+ 类型: groupData.groupType,
|
|
|
|
+ 状态: '已启用',
|
|
|
|
+ 添加时间: new Date().toLocaleString(),
|
|
|
|
+ 操作者: msg.from.username || msg.from.first_name + ' (' + msg.from.id + ')'
|
|
|
|
+ }));
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ // 尝试发送欢迎消息
|
|
|
|
+ const welcomeMessage = await bot.sendMessage(chatId, '感谢添加我为群组成员!使用 /help 查看可用命令。', {
|
|
|
|
+ parse_mode: 'HTML'
|
|
|
|
+ });
|
|
|
|
+ console.log(formatLog(welcomeMessage));
|
|
|
|
+
|
|
|
|
+ // 尝试发送账单消息
|
|
|
|
+ const billMessage = await generateBillMessage(chatId);
|
|
|
|
+ if (billMessage) {
|
|
|
|
+ const billResult = await bot.sendMessage(chatId, billMessage, {
|
|
|
|
+ parse_mode: 'HTML',
|
|
|
|
+ reply_markup: generateInlineKeyboard(chatId)
|
|
|
|
+ });
|
|
|
|
+ console.log(formatLog(billResult));
|
|
|
|
+ }
|
|
|
|
+ } catch (messageError) {
|
|
|
|
+ console.error(formatLog(messageError));
|
|
|
|
+ }
|
|
|
|
+ } catch (error) {
|
|
|
|
+ console.error(formatLog('创建群组过程中出错', error));
|
|
|
|
+ try {
|
|
|
|
+ await bot.sendMessage(chatId, '添加群组失败,请联系管理员。', {
|
|
|
|
+ parse_mode: 'HTML'
|
|
|
|
+ });
|
|
|
|
+ } catch (messageError) {
|
|
|
|
+ console.error(formatLog('发送错误消息失败', messageError));
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} catch (error) {
|
|
} catch (error) {
|
|
- console.error('处理群组加入失败:', error);
|
|
|
|
|
|
+ console.error(formatLog('处理群组加入失败', error));
|
|
await sendMessage(chatId, '添加群组失败,请联系管理员。');
|
|
await sendMessage(chatId, '添加群组失败,请联系管理员。');
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
// 其他新成员
|
|
// 其他新成员
|
|
- console.log(`新成员加入群组: ${member.username || member.first_name} (${member.id})`);
|
|
|
|
|
|
+ console.log(formatLog({
|
|
|
|
+ member: member.username || member.first_name + ' (' + member.id + ')'
|
|
|
|
+ }));
|
|
await sendMessage(chatId, `欢迎 ${member.username || member.first_name} 加入群组!`);
|
|
await sendMessage(chatId, `欢迎 ${member.username || member.first_name} 加入群组!`);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
|
|
|
|
+// 处理机器人被移出群组
|
|
|
|
+bot.on('left_chat_member', async (msg) => {
|
|
|
|
+ if (msg.left_chat_member.id === (await bot.getMe()).id) {
|
|
|
|
+ const chatId = msg.chat.id.toString();
|
|
|
|
+ try {
|
|
|
|
+ // 更新数据库中的群组状态
|
|
|
|
+ await pool.query(`
|
|
|
|
+ UPDATE groups
|
|
|
|
+ SET is_active = false,
|
|
|
|
+ last_leave_time = CURRENT_TIMESTAMP
|
|
|
|
+ WHERE group_id = ?
|
|
|
|
+ `, [chatId]);
|
|
|
|
+
|
|
|
|
+ // 从内存中的允许列表中移除
|
|
|
|
+ const index = data.allowedGroups.indexOf(chatId);
|
|
|
|
+ if (index > -1) {
|
|
|
|
+ data.allowedGroups.splice(index, 1);
|
|
|
|
+ saveData();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // console.log(formatLog({
|
|
|
|
+ // ID: chatId,
|
|
|
|
+ // 名称: msg.chat.title || '未命名群组',
|
|
|
|
+ // 类型: msg.chat.type,
|
|
|
|
+ // 状态: '已移除',
|
|
|
|
+ // 移除时间: new Date().toLocaleString(),
|
|
|
|
+ // 操作者: msg.from.username || msg.from.first_name + ' (' + msg.from.id + ')'
|
|
|
|
+ // }));
|
|
|
|
+ } catch (error) {
|
|
|
|
+ console.error(formatLog('处理机器人被移出群组失败', error));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+});
|
|
|
|
+
|
|
// 处理管理员命令
|
|
// 处理管理员命令
|
|
bot.onText(/\/addgroup (.+)/, async (msg, match) => {
|
|
bot.onText(/\/addgroup (.+)/, async (msg, match) => {
|
|
if (!isAdmin(msg.from.id)) {
|
|
if (!isAdmin(msg.from.id)) {
|
|
@@ -243,17 +381,26 @@ bot.onText(/\/addgroup (.+)/, async (msg, match) => {
|
|
groupType: 'public',
|
|
groupType: 'public',
|
|
creatorId: msg.from.id.toString()
|
|
creatorId: msg.from.id.toString()
|
|
};
|
|
};
|
|
-
|
|
|
|
- const result = await createGroup({ body: groupData });
|
|
|
|
|
|
+
|
|
|
|
+ const result = await createGroup({
|
|
|
|
+ body: groupData
|
|
|
|
+ });
|
|
if (result) {
|
|
if (result) {
|
|
data.allowedGroups.push(groupId);
|
|
data.allowedGroups.push(groupId);
|
|
saveData();
|
|
saveData();
|
|
|
|
+ console.log(formatLog({
|
|
|
|
+ ID: groupId,
|
|
|
|
+ 名称: groupData.groupName,
|
|
|
|
+ 状态: '已启用',
|
|
|
|
+ 添加时间: new Date().toLocaleString(),
|
|
|
|
+ 操作者: msg.from.username || msg.from.first_name + ' (' + msg.from.id + ')'
|
|
|
|
+ }));
|
|
sendMessage(msg.chat.id, `群组 ${groupId} 已添加到允许列表。`);
|
|
sendMessage(msg.chat.id, `群组 ${groupId} 已添加到允许列表。`);
|
|
} else {
|
|
} else {
|
|
sendMessage(msg.chat.id, '添加群组失败,请检查群组ID是否正确。');
|
|
sendMessage(msg.chat.id, '添加群组失败,请检查群组ID是否正确。');
|
|
}
|
|
}
|
|
} catch (error) {
|
|
} catch (error) {
|
|
- console.error('创建群组失败:', error);
|
|
|
|
|
|
+ console.error(formatLog('创建群组失败', error));
|
|
sendMessage(msg.chat.id, '添加群组失败,请稍后重试。');
|
|
sendMessage(msg.chat.id, '添加群组失败,请稍后重试。');
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
@@ -261,62 +408,6 @@ bot.onText(/\/addgroup (.+)/, async (msg, match) => {
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
|
|
-bot.onText(/\/removegroup (.+)/, async (msg, match) => {
|
|
|
|
- if (!isAdmin(msg.from.id)) {
|
|
|
|
- sendMessage(msg.chat.id, '您没有权限执行此命令。');
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- const groupId = match[1].trim();
|
|
|
|
- try {
|
|
|
|
- // 使用 updateGroup 更新群组状态
|
|
|
|
- const result = await updateGroup({
|
|
|
|
- params: { id: groupId },
|
|
|
|
- body: { isActive: false }
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- if (result) {
|
|
|
|
- const index = data.allowedGroups.indexOf(groupId);
|
|
|
|
- if (index > -1) {
|
|
|
|
- data.allowedGroups.splice(index, 1);
|
|
|
|
- saveData();
|
|
|
|
- sendMessage(msg.chat.id, `群组 ${groupId} 已从允许列表中移除。`);
|
|
|
|
- } else {
|
|
|
|
- sendMessage(msg.chat.id, '该群组不在允许列表中。');
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- sendMessage(msg.chat.id, '移除群组失败,请稍后重试。');
|
|
|
|
- }
|
|
|
|
- } catch (error) {
|
|
|
|
- console.error('更新群组状态失败:', error);
|
|
|
|
- sendMessage(msg.chat.id, '移除群组失败,请稍后重试。');
|
|
|
|
- }
|
|
|
|
-});
|
|
|
|
-
|
|
|
|
-bot.onText(/\/listgroups/, async (msg) => {
|
|
|
|
- if (!isAdmin(msg.from.id)) {
|
|
|
|
- sendMessage(msg.chat.id, '您没有权限执行此命令。');
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- try {
|
|
|
|
- const groups = await pool.query('SELECT group_id, group_name, group_type, is_active FROM groups WHERE is_active = 1');
|
|
|
|
- if (groups.length === 0) {
|
|
|
|
- sendMessage(msg.chat.id, '当前没有允许的群组。');
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- const groupsList = groups.map(group =>
|
|
|
|
- `ID: ${group.group_id}\n名称: ${group.group_name}\n类型: ${group.group_type}\n状态: ${group.is_active ? '启用' : '禁用'}`
|
|
|
|
- ).join('\n\n');
|
|
|
|
-
|
|
|
|
- sendMessage(msg.chat.id, `允许的群组列表:\n\n${groupsList}`);
|
|
|
|
- } catch (error) {
|
|
|
|
- console.error('获取群组列表失败:', error);
|
|
|
|
- sendMessage(msg.chat.id, '获取群组列表失败,请稍后重试。');
|
|
|
|
- }
|
|
|
|
-});
|
|
|
|
-
|
|
|
|
// 处理入款命令
|
|
// 处理入款命令
|
|
bot.onText(/\/deposit (.+)/, async (msg, match) => {
|
|
bot.onText(/\/deposit (.+)/, async (msg, match) => {
|
|
if (!isGroupAllowed(msg.chat.id)) {
|
|
if (!isGroupAllowed(msg.chat.id)) {
|
|
@@ -354,7 +445,7 @@ bot.onText(/\/deposit (.+)/, async (msg, match) => {
|
|
console.log(`入款失败 - 群组: ${msg.chat.title}, 金额: ${amount}, 原因: ${result.message}, 时间: ${new Date().toLocaleString()}`);
|
|
console.log(`入款失败 - 群组: ${msg.chat.title}, 金额: ${amount}, 原因: ${result.message}, 时间: ${new Date().toLocaleString()}`);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
} catch (error) {
|
|
- console.error('记录入款失败:', error);
|
|
|
|
|
|
+ console.error(formatLog('记录入款失败', error));
|
|
await sendMessage(msg.chat.id, '记录入款失败,请稍后重试');
|
|
await sendMessage(msg.chat.id, '记录入款失败,请稍后重试');
|
|
}
|
|
}
|
|
});
|
|
});
|
|
@@ -396,7 +487,7 @@ bot.onText(/\/withdraw (.+)/, async (msg, match) => {
|
|
console.log(`出款失败 - 群组: ${msg.chat.title}, 金额: ${amount}, 原因: ${result.message}, 时间: ${new Date().toLocaleString()}`);
|
|
console.log(`出款失败 - 群组: ${msg.chat.title}, 金额: ${amount}, 原因: ${result.message}, 时间: ${new Date().toLocaleString()}`);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
} catch (error) {
|
|
- console.error('记录出款失败:', error);
|
|
|
|
|
|
+ console.error(formatLog('记录出款失败', error));
|
|
await sendMessage(msg.chat.id, '记录出款失败,请稍后重试');
|
|
await sendMessage(msg.chat.id, '记录出款失败,请稍后重试');
|
|
}
|
|
}
|
|
});
|
|
});
|
|
@@ -468,7 +559,7 @@ async function generateBillMessage(chatId) {
|
|
|
|
|
|
const deposits = records.filter(r => r.type === 'deposit');
|
|
const deposits = records.filter(r => r.type === 'deposit');
|
|
const withdrawals = records.filter(r => r.type === 'withdrawal');
|
|
const withdrawals = records.filter(r => r.type === 'withdrawal');
|
|
-
|
|
|
|
|
|
+
|
|
const totalDeposit = deposits.reduce((sum, d) => sum + parseFloat(d.amount), 0);
|
|
const totalDeposit = deposits.reduce((sum, d) => sum + parseFloat(d.amount), 0);
|
|
const totalWithdrawal = withdrawals.reduce((sum, w) => sum + parseFloat(w.amount), 0);
|
|
const totalWithdrawal = withdrawals.reduce((sum, w) => sum + parseFloat(w.amount), 0);
|
|
const depositFee = totalDeposit * (feeRate / 100);
|
|
const depositFee = totalDeposit * (feeRate / 100);
|
|
@@ -507,7 +598,7 @@ async function generateBillMessage(chatId) {
|
|
|
|
|
|
return message;
|
|
return message;
|
|
} catch (error) {
|
|
} catch (error) {
|
|
- console.error('生成账单消息失败:', error);
|
|
|
|
|
|
+ console.error(formatLog('生成账单消息失败', error));
|
|
return '获取账单信息失败,请稍后重试';
|
|
return '获取账单信息失败,请稍后重试';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -516,18 +607,14 @@ async function generateBillMessage(chatId) {
|
|
function generateInlineKeyboard(chatId) {
|
|
function generateInlineKeyboard(chatId) {
|
|
const keyboard = {
|
|
const keyboard = {
|
|
inline_keyboard: [
|
|
inline_keyboard: [
|
|
- [
|
|
|
|
- {
|
|
|
|
- text: '点击跳转完整账单',
|
|
|
|
- callback_data: `bill_page_${chatId}`
|
|
|
|
- }
|
|
|
|
- ],
|
|
|
|
- [
|
|
|
|
- {
|
|
|
|
- text: '24小时商务对接',
|
|
|
|
- callback_data: 'business_contact'
|
|
|
|
- }
|
|
|
|
- ]
|
|
|
|
|
|
+ [{
|
|
|
|
+ text: '点击跳转完整账单',
|
|
|
|
+ callback_data: `bill_page_${chatId}`
|
|
|
|
+ }],
|
|
|
|
+ [{
|
|
|
|
+ text: '24小时商务对接',
|
|
|
|
+ callback_data: 'business_contact'
|
|
|
|
+ }]
|
|
]
|
|
]
|
|
};
|
|
};
|
|
return keyboard;
|
|
return keyboard;
|
|
@@ -550,7 +637,7 @@ bot.on('callback_query', async (callbackQuery) => {
|
|
});
|
|
});
|
|
}
|
|
}
|
|
} catch (error) {
|
|
} catch (error) {
|
|
- console.error('处理内联按钮回调失败:', error);
|
|
|
|
|
|
+ console.error(formatLog('处理内联按钮回调失败', error));
|
|
await bot.answerCallbackQuery(callbackQuery.id, {
|
|
await bot.answerCallbackQuery(callbackQuery.id, {
|
|
text: '操作失败,请稍后重试',
|
|
text: '操作失败,请稍后重试',
|
|
show_alert: true
|
|
show_alert: true
|
|
@@ -563,7 +650,7 @@ function saveData() {
|
|
try {
|
|
try {
|
|
fs.writeFileSync(process.env.DB_FILE, JSON.stringify(data, null, 2));
|
|
fs.writeFileSync(process.env.DB_FILE, JSON.stringify(data, null, 2));
|
|
} catch (error) {
|
|
} catch (error) {
|
|
- console.error('Error saving data:', error);
|
|
|
|
|
|
+ console.error(formatLog('Error saving data', error));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -572,10 +659,13 @@ function loadData() {
|
|
try {
|
|
try {
|
|
if (fs.existsSync(process.env.DB_FILE)) {
|
|
if (fs.existsSync(process.env.DB_FILE)) {
|
|
const savedData = JSON.parse(fs.readFileSync(process.env.DB_FILE));
|
|
const savedData = JSON.parse(fs.readFileSync(process.env.DB_FILE));
|
|
- data = { ...data, ...savedData };
|
|
|
|
|
|
+ data = {
|
|
|
|
+ ...data,
|
|
|
|
+ ...savedData
|
|
|
|
+ };
|
|
}
|
|
}
|
|
} catch (error) {
|
|
} catch (error) {
|
|
- console.error('Error loading data:', error);
|
|
|
|
|
|
+ console.error(formatLog('Error loading data', error));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -585,15 +675,272 @@ testConnection().then(() => {
|
|
}).then(() => {
|
|
}).then(() => {
|
|
// 加载数据
|
|
// 加载数据
|
|
loadData();
|
|
loadData();
|
|
-
|
|
|
|
|
|
+
|
|
// 启动服务器
|
|
// 启动服务器
|
|
const PORT = process.env.PORT || 3000;
|
|
const PORT = process.env.PORT || 3000;
|
|
app.listen(PORT, () => {
|
|
app.listen(PORT, () => {
|
|
- console.log(`服务器运行在端口 ${PORT}`);
|
|
|
|
|
|
+ console.log(formatLog({
|
|
|
|
+ PORT: PORT
|
|
|
|
+ }));
|
|
console.log('机器人已准备就绪!');
|
|
console.log('机器人已准备就绪!');
|
|
});
|
|
});
|
|
}).catch(error => {
|
|
}).catch(error => {
|
|
- console.error('启动失败:', error);
|
|
|
|
|
|
+ console.error(formatLog('启动失败', error));
|
|
process.exit(1);
|
|
process.exit(1);
|
|
-});
|
|
|
|
|
|
+});
|
|
|
|
+
|
|
|
|
+// 处理机器人被添加到群组
|
|
|
|
+async function handleBotAdded(msg, chatId, chatType, chatIdStr, existingGroup) {
|
|
|
|
+ try {
|
|
|
|
+ // 获取群组链接
|
|
|
|
+ const chatInfo = await bot.getChat(chatId);
|
|
|
|
+ const groupInfo = {
|
|
|
|
+ ID: chatId,
|
|
|
|
+ 名称: msg.chat.title || '未命名群组',
|
|
|
|
+ 类型: chatType,
|
|
|
|
+ 状态: existingGroup ? '重新激活' : '已激活',
|
|
|
|
+ 群组链接: chatInfo.invite_link || '未设置',
|
|
|
|
+ 更新时间: new Date().toLocaleString()
|
|
|
|
+ };
|
|
|
|
+ // console.log('机器人首次被添加到群组');
|
|
|
|
+ // console.log(formatLog(groupInfo));
|
|
|
|
+
|
|
|
|
+ // 如果群组不存在,创建新群组
|
|
|
|
+ if (!existingGroup) {
|
|
|
|
+ const groupData = {
|
|
|
|
+ groupId: chatIdStr,
|
|
|
|
+ groupName: msg.chat.title || '未命名群组',
|
|
|
|
+ groupType: chatType === 'private' ? 'private' : 'public',
|
|
|
|
+ creatorId: msg.from.id.toString()
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ const id = await Group.create({
|
|
|
|
+ groupId: groupData.groupId,
|
|
|
|
+ groupName: groupData.groupName,
|
|
|
|
+ creatorId: groupData.creatorId
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ if (id) {
|
|
|
|
+ // 更新内存中的群组列表
|
|
|
|
+ if (!data.allowedGroups.includes(chatIdStr)) {
|
|
|
|
+ data.allowedGroups.push(chatIdStr);
|
|
|
|
+ saveData();
|
|
|
|
+ }
|
|
|
|
+ console.log('机器人首次被添加到群组');
|
|
|
|
+ console.log(formatLog(groupInfo));
|
|
|
|
+ await sendMessage(chatId, '感谢添加我为群组成员!使用 /help 查看可用命令。');
|
|
|
|
+ } else {
|
|
|
|
+ await sendMessage(chatId, '添加群组失败,请联系管理员。');
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } catch (error) {
|
|
|
|
+ console.error(formatLog({
|
|
|
|
+ 错误: '处理机器人首次加入群组失败',
|
|
|
|
+ 详情: error.message
|
|
|
|
+ }));
|
|
|
|
+ await sendMessage(chatId, '添加群组失败,请联系管理员。');
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 处理群组信息更新
|
|
|
|
+async function handleGroupUpdate(msg, chatId, chatType, chatIdStr, existingGroup, newStatus) {
|
|
|
|
+ const connection = await pool.getConnection();
|
|
|
|
+ await connection.beginTransaction();
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ // 更新群组ID和类型
|
|
|
|
+ const newType = chatType === 'private' ? 'private' :
|
|
|
|
+ chatType === 'supergroup' ? 'supergroup' : 'group';
|
|
|
|
+ const oldGroupId = existingGroup.group_id;
|
|
|
|
+
|
|
|
|
+ // 如果群组ID发生变化,更新所有相关记录
|
|
|
|
+ if (existingGroup.group_type != newType) {
|
|
|
|
+ console.log(formatLog({
|
|
|
|
+ 操作: '群组类型更新',
|
|
|
|
+ 名称: msg.chat.title || existingGroup.group_name,
|
|
|
|
+ 旧ID: oldGroupId,
|
|
|
|
+ 新ID: chatIdStr,
|
|
|
|
+ 旧类型: existingGroup.group_type,
|
|
|
|
+ 新类型: newType,
|
|
|
|
+ 状态: newStatus !== 'kicked' && newStatus !== 'left' ? '活跃' : '已移除'
|
|
|
|
+ }));
|
|
|
|
+
|
|
|
|
+ // 开始事务
|
|
|
|
+ await connection.beginTransaction();
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ // 检查目标ID是否已存在
|
|
|
|
+ const [existingTargetGroup] = await connection.query(
|
|
|
|
+ 'SELECT * FROM groups WHERE group_id = ?',
|
|
|
|
+ [chatIdStr]
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ if (existingTargetGroup && existingTargetGroup.length > 0) {
|
|
|
|
+ // 更新交易记录
|
|
|
|
+ await connection.query(`
|
|
|
|
+ UPDATE transactions
|
|
|
|
+ SET group_id = ?
|
|
|
|
+ WHERE group_id = ?
|
|
|
|
+ `, [chatIdStr, oldGroupId]);
|
|
|
|
+
|
|
|
|
+ // 更新资金记录
|
|
|
|
+ await connection.query(`
|
|
|
|
+ UPDATE money_records
|
|
|
|
+ SET group_id = ?
|
|
|
|
+ WHERE group_id = ?
|
|
|
|
+ `, [chatIdStr, oldGroupId]);
|
|
|
|
+
|
|
|
|
+ // 删除旧群组记录
|
|
|
|
+ await connection.query(
|
|
|
|
+ 'DELETE FROM groups WHERE group_id = ?',
|
|
|
|
+ [oldGroupId]
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ // 更新目标群组信息
|
|
|
|
+ await connection.query(`
|
|
|
|
+ UPDATE groups
|
|
|
|
+ SET group_type = ?,
|
|
|
|
+ group_name = ?,
|
|
|
|
+ is_active = ?,
|
|
|
|
+ updated_at = CURRENT_TIMESTAMP
|
|
|
|
+ WHERE group_id = ?
|
|
|
|
+ `, [
|
|
|
|
+ newType,
|
|
|
|
+ msg.chat.title || existingGroup.group_name,
|
|
|
|
+ newStatus !== 'kicked' && newStatus !== 'left',
|
|
|
|
+ chatIdStr
|
|
|
|
+ ]);
|
|
|
|
+ } else {
|
|
|
|
+ // 如果目标ID不存在,执行正常的更新操作
|
|
|
|
+ // 先删除旧记录
|
|
|
|
+ await connection.query(
|
|
|
|
+ 'DELETE FROM groups WHERE group_id = ?',
|
|
|
|
+ [oldGroupId]
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ // 插入新记录
|
|
|
|
+ await connection.query(`
|
|
|
|
+ INSERT INTO groups
|
|
|
|
+ (group_id, group_name, group_type, creator_id, is_active, last_join_time)
|
|
|
|
+ VALUES (?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
|
|
|
|
+ `, [
|
|
|
|
+ chatIdStr,
|
|
|
|
+ msg.chat.title || existingGroup.group_name,
|
|
|
|
+ newType,
|
|
|
|
+ existingGroup.creator_id,
|
|
|
|
+ newStatus !== 'kicked' && newStatus !== 'left'
|
|
|
|
+ ]);
|
|
|
|
+
|
|
|
|
+ // 更新交易记录
|
|
|
|
+ await connection.query(`
|
|
|
|
+ UPDATE transactions
|
|
|
|
+ SET group_id = ?
|
|
|
|
+ WHERE group_id = ?
|
|
|
|
+ `, [chatIdStr, oldGroupId]);
|
|
|
|
|
|
|
|
+ // 更新资金记录
|
|
|
|
+ await connection.query(`
|
|
|
|
+ UPDATE money_records
|
|
|
|
+ SET group_id = ?
|
|
|
|
+ WHERE group_id = ?
|
|
|
|
+ `, [chatIdStr, oldGroupId]);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 提交事务
|
|
|
|
+ await connection.commit();
|
|
|
|
+
|
|
|
|
+ // 更新内存中的群组列表
|
|
|
|
+ const index = data.allowedGroups.indexOf(oldGroupId);
|
|
|
|
+ if (index > -1) {
|
|
|
|
+ if (newStatus === 'kicked' || newStatus === 'left') {
|
|
|
|
+ data.allowedGroups.splice(index, 1);
|
|
|
|
+ } else {
|
|
|
|
+ data.allowedGroups[index] = chatIdStr;
|
|
|
|
+ }
|
|
|
|
+ saveData();
|
|
|
|
+ }
|
|
|
|
+ } catch (error) {
|
|
|
|
+ // 回滚事务
|
|
|
|
+ await connection.rollback();
|
|
|
|
+ console.error(formatLog('更新群组信息失败', error));
|
|
|
|
+ throw error;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ // 如果ID没有变化,只更新其他信息
|
|
|
|
+ await connection.query(`
|
|
|
|
+ UPDATE groups
|
|
|
|
+ SET group_type = ?,
|
|
|
|
+ group_name = ?,
|
|
|
|
+ is_active = ?,
|
|
|
|
+ updated_at = CURRENT_TIMESTAMP
|
|
|
|
+ WHERE group_id = ?
|
|
|
|
+ `, [
|
|
|
|
+ newType,
|
|
|
|
+ msg.chat.title || existingGroup.group_name,
|
|
|
|
+ newStatus !== 'kicked' && newStatus !== 'left',
|
|
|
|
+ chatIdStr
|
|
|
|
+ ]);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ await connection.commit();
|
|
|
|
+ console.log('【群组状态变更】');
|
|
|
|
+ console.log(formatLog({
|
|
|
|
+ ID: oldGroupId + ' -> ' + chatIdStr,
|
|
|
|
+ type: existingGroup.group_type + ' -> ' + newType,
|
|
|
|
+ name: existingGroup.group_name + ' -> ' + msg.chat.title || existingGroup.group_name,
|
|
|
|
+ status: newStatus === 'kicked' || newStatus === 'left' ? '已移除' : '活跃'
|
|
|
|
+ }));
|
|
|
|
+ } catch (error) {
|
|
|
|
+ await connection.rollback();
|
|
|
|
+ console.error(formatLog({
|
|
|
|
+ 错误: '更新群组信息失败',
|
|
|
|
+ 详情: error.message
|
|
|
|
+ }));
|
|
|
|
+ throw error;
|
|
|
|
+ } finally {
|
|
|
|
+ connection.release();
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 处理群组状态变更
|
|
|
|
+bot.on('my_chat_member', async (msg) => {
|
|
|
|
+ try {
|
|
|
|
+ const chatId = msg.chat.id;
|
|
|
|
+ const newStatus = msg.new_chat_member.status;
|
|
|
|
+ const oldStatus = msg.old_chat_member.status;
|
|
|
|
+ const chatType = msg.chat.type;
|
|
|
|
+ const chatIdStr = chatId.toString();
|
|
|
|
+
|
|
|
|
+ // 查找群组,同时检查新旧ID
|
|
|
|
+ const existingGroup = await Group.findByGroupId(chatIdStr) ||
|
|
|
|
+ await Group.findByGroupId(chatIdStr.replace('-', ''));
|
|
|
|
+
|
|
|
|
+ // 获取群组详细信息(如果机器人还在群组中)
|
|
|
|
+ if (newStatus !== 'kicked' && newStatus !== 'left') {
|
|
|
|
+ try {
|
|
|
|
+ const chatInfo = await bot.getChat(chatId);
|
|
|
|
+ } catch (error) {
|
|
|
|
+ console.log(formatLog('获取群组详细信息失败', error.message));
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ console.log('机器人已被移出群组,无法获取详细信息');
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const newType = chatType === 'private' ? 'private' :
|
|
|
|
+ chatType === 'supergroup' ? 'supergroup' : 'group';
|
|
|
|
+
|
|
|
|
+ // 如果是机器人首次被添加到群组(从非成员变为成员)
|
|
|
|
+ if (oldStatus === 'left' && newStatus === 'member' && existingGroup.group_type != newType) {
|
|
|
|
+ await handleBotAdded(msg, chatId, chatType, chatIdStr, existingGroup);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (existingGroup) {
|
|
|
|
+ await handleGroupUpdate(msg, chatId, chatType, chatIdStr, existingGroup, newStatus);
|
|
|
|
+ }
|
|
|
|
+ } catch (error) {
|
|
|
|
+ console.error(formatLog({
|
|
|
|
+ 错误: '处理群组状态变更失败',
|
|
|
|
+ 详情: error.message
|
|
|
|
+ }));
|
|
|
|
+ }
|
|
|
|
+});
|