|
@@ -69,11 +69,7 @@ function isGroupAllowed(chatId) {
|
|
|
data.allowedGroups.includes(chatIdStr.replace('-', ''));
|
|
|
}
|
|
|
|
|
|
-// 检查是否是管理员
|
|
|
-function isAdmin(userId) {
|
|
|
- return process.env.ADMIN_IDS.split(',').includes(userId.toString());
|
|
|
-}
|
|
|
-
|
|
|
+// 前置处理
|
|
|
// 检查用户是否有权限操作机器人
|
|
|
async function checkUserPermission(chatId, userId) {
|
|
|
try {
|
|
@@ -91,8 +87,6 @@ async function checkUserPermission(chatId, userId) {
|
|
|
const userIdStr = userId.toString();
|
|
|
const isCreator = groupInfo.creator_id === userIdStr;
|
|
|
|
|
|
- console.log(`权限检查 - 用户ID: ${userIdStr}, 创建者ID: ${groupInfo.creator_id}, 是否创建者: ${isCreator}`);
|
|
|
-
|
|
|
let operators = [];
|
|
|
try {
|
|
|
if (groupInfo.operators) {
|
|
@@ -106,13 +100,12 @@ async function checkUserPermission(chatId, userId) {
|
|
|
operators = [];
|
|
|
}
|
|
|
|
|
|
- const isOperator = operators.some(op => {
|
|
|
- const isOp = op.operator_id === userIdStr;
|
|
|
- console.log(`检查操作人 - 操作人ID: ${op.operator_id}, 用户ID: ${userIdStr}, 是否匹配: ${isOp}`);
|
|
|
- return isOp;
|
|
|
- });
|
|
|
+ const isOperator = operators.some(op => op.operator_id === userIdStr);
|
|
|
|
|
|
- console.log(`权限检查结果 - 用户ID: ${userIdStr}, 是否创建者: ${isCreator}, 是否操作人: ${isOperator}`);
|
|
|
+ // 只在权限检查失败时输出详细日志
|
|
|
+ if (!isCreator && !isOperator) {
|
|
|
+ console.log(`权限检查失败 - 用户ID: ${userIdStr}, 群组ID: ${chatId}, 创建者ID: ${groupInfo.creator_id}, 操作人数量: ${operators.length}`);
|
|
|
+ }
|
|
|
|
|
|
return isCreator || isOperator;
|
|
|
} catch (error) {
|
|
@@ -120,7 +113,6 @@ async function checkUserPermission(chatId, userId) {
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
// 处理消息发送
|
|
|
async function sendMessage(chatId, text, options = {}) {
|
|
|
try {
|
|
@@ -153,24 +145,21 @@ async function sendMessage(chatId, text, options = {}) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// 处理快捷命令
|
|
|
+// - 1.快捷命令
|
|
|
bot.on('message', async (msg) => {
|
|
|
if (!isGroupAllowed(msg.chat.id)) return;
|
|
|
|
|
|
const text = msg.text?.trim();
|
|
|
if (!text) return;
|
|
|
|
|
|
- // 检查用户权限
|
|
|
+ // 0. 检查用户权限
|
|
|
const hasPermission = await checkUserPermission(msg.chat.id, msg.from.id);
|
|
|
- console.log(`用户权限检查 - 用户ID: ${msg.from.id}, 群组ID: ${msg.chat.id}, 是否有权限: ${hasPermission}`);
|
|
|
-
|
|
|
if (!hasPermission) {
|
|
|
// 如果不是创建人或操作人,直接返回
|
|
|
- console.log(`用户无权限操作 - 用户ID: ${msg.from.id}, 群组ID: ${msg.chat.id}`);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- // 处理入款命令
|
|
|
+ // 1. 处理入款命令
|
|
|
if (text.startsWith('+')) {
|
|
|
let amount, exchangeRate, feeRate;
|
|
|
const parts = text.substring(1).split('/');
|
|
@@ -222,7 +211,7 @@ bot.on('message', async (msg) => {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- // 处理入款修正命令
|
|
|
+ // 1.1 处理入款修正命令
|
|
|
else if (text.startsWith('-') && !text.includes('下发')) {
|
|
|
let amount, exchangeRate, feeRate;
|
|
|
const parts = text.substring(1).split('/');
|
|
@@ -272,7 +261,8 @@ bot.on('message', async (msg) => {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- // 处理回款命令
|
|
|
+
|
|
|
+ // 2. 处理回款命令
|
|
|
else if (text.startsWith('下发')) {
|
|
|
let amount, exchangeRate, feeRate;
|
|
|
const parts = text.replace(/[^0-9./-]/g, '').split('/');
|
|
@@ -322,7 +312,7 @@ bot.on('message', async (msg) => {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- // 处理回款修正命令
|
|
|
+ // 2.1 处理回款修正命令
|
|
|
else if (text.startsWith('下发-')) {
|
|
|
let amount, exchangeRate, feeRate;
|
|
|
const parts = text.replace(/[^0-9./-]/g, '').split('/');
|
|
@@ -372,7 +362,8 @@ bot.on('message', async (msg) => {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- // 处理设置费率命令
|
|
|
+
|
|
|
+ // 3. 处理设置费率命令
|
|
|
else if (text.startsWith('设置费率')) {
|
|
|
const feeRate = parseFloat(text.replace('设置费率', '').trim());
|
|
|
|
|
@@ -397,7 +388,8 @@ bot.on('message', async (msg) => {
|
|
|
await sendMessage(msg.chat.id, '费率设置失败,请输入0-100之间的数字');
|
|
|
}
|
|
|
}
|
|
|
- // 处理设置汇率命令
|
|
|
+
|
|
|
+ // 4. 处理设置汇率命令
|
|
|
else if (text.startsWith('设置汇率')) {
|
|
|
const exchangeRate = parseFloat(text.replace('设置汇率', '').trim());
|
|
|
|
|
@@ -422,7 +414,8 @@ bot.on('message', async (msg) => {
|
|
|
await sendMessage(msg.chat.id, '汇率设置失败,请输入大于0的数字');
|
|
|
}
|
|
|
}
|
|
|
- // 处理设置操作人命令
|
|
|
+
|
|
|
+ // 5. 处理设置操作人命令
|
|
|
else if (text.startsWith('设置操作人')) {
|
|
|
try {
|
|
|
const groupId = msg.chat.id.toString();
|
|
@@ -532,7 +525,8 @@ bot.on('message', async (msg) => {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- // 处理TRX地址
|
|
|
+
|
|
|
+ // 6. 处理TRX地址
|
|
|
else if (/^T[A-Za-z0-9]{33}$/.test(text)) {
|
|
|
try {
|
|
|
const groupId = msg.chat.id.toString();
|
|
@@ -572,120 +566,7 @@ bot.on('message', async (msg) => {
|
|
|
}
|
|
|
});
|
|
|
|
|
|
-// 处理机器人被移出群组
|
|
|
-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) => {
|
|
|
- if (!isAdmin(msg.from.id)) {
|
|
|
- sendMessage(msg.chat.id, '您没有权限执行此命令。');
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- const groupId = match[1].trim();
|
|
|
- if (!data.allowedGroups.includes(groupId)) {
|
|
|
- try {
|
|
|
- // 使用 createGroup 创建新群组
|
|
|
- const groupData = {
|
|
|
- groupId: groupId,
|
|
|
- groupName: '手动添加的群组',
|
|
|
- groupType: 'public',
|
|
|
- creatorId: msg.from.id.toString()
|
|
|
- };
|
|
|
-
|
|
|
- const result = await createGroup({
|
|
|
- body: groupData
|
|
|
- });
|
|
|
- if (result) {
|
|
|
- data.allowedGroups.push(groupId);
|
|
|
- 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} 已添加到允许列表。`);
|
|
|
- } else {
|
|
|
- sendMessage(msg.chat.id, '添加群组失败,请检查群组ID是否正确。');
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- console.error(formatLog('创建群组失败', error));
|
|
|
- sendMessage(msg.chat.id, '添加群组失败,请稍后重试。');
|
|
|
- }
|
|
|
- } else {
|
|
|
- sendMessage(msg.chat.id, '该群组已在允许列表中。');
|
|
|
- }
|
|
|
-});
|
|
|
-
|
|
|
-// 处理查看账单命令
|
|
|
-bot.onText(/\/bill/, async (msg) => {
|
|
|
- const billMessage = await generateBillMessage(msg.chat.id);
|
|
|
- sendMessage(msg.chat.id, billMessage, {
|
|
|
- reply_markup: generateInlineKeyboard(msg.chat.id)
|
|
|
- });
|
|
|
-});
|
|
|
-
|
|
|
-// 更新帮助命令
|
|
|
-bot.onText(/\/help/, (msg) => {
|
|
|
- const helpMessage = `
|
|
|
-🤖 机器人使用指南
|
|
|
-
|
|
|
-📝 基础命令
|
|
|
-• /deposit 数字 - 记录入款
|
|
|
-• /withdraw 数字 - 记录下发
|
|
|
-• /bill - 查看当前账单
|
|
|
-• /help - 显示此帮助信息
|
|
|
-
|
|
|
-⚡️ 快捷命令
|
|
|
-• +数字 - 快速记录入款(例如:+2000)
|
|
|
-• -数字 - 快速记录下发(例如:-2000)
|
|
|
-
|
|
|
-👨💼 管理员命令
|
|
|
-• /addgroup 群组ID - 添加允许的群组
|
|
|
-• /removegroup 群组ID - 移除允许的群组
|
|
|
-• /listgroups - 列出所有允许的群组
|
|
|
-
|
|
|
-💡 使用提示
|
|
|
-• 所有金额输入请使用数字
|
|
|
-• 账单信息实时更新
|
|
|
-• 如需帮助请联系管理员
|
|
|
- `;
|
|
|
- sendMessage(msg.chat.id, helpMessage);
|
|
|
-});
|
|
|
-
|
|
|
+// - 2.查看账单
|
|
|
// 生成账单消息
|
|
|
async function generateBillMessage(chatId) {
|
|
|
try {
|
|
@@ -782,7 +663,6 @@ async function generateBillMessage(chatId) {
|
|
|
return '获取账单信息失败,请稍后重试';
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
// 生成内联键盘
|
|
|
function generateInlineKeyboard(chatId) {
|
|
|
const keyboard = {
|
|
@@ -799,7 +679,6 @@ function generateInlineKeyboard(chatId) {
|
|
|
};
|
|
|
return keyboard;
|
|
|
}
|
|
|
-
|
|
|
// 处理内联按钮回调
|
|
|
bot.on('callback_query', async (callbackQuery) => {
|
|
|
const chatId = callbackQuery.message.chat.id;
|
|
@@ -824,52 +703,43 @@ bot.on('callback_query', async (callbackQuery) => {
|
|
|
});
|
|
|
}
|
|
|
});
|
|
|
+bot.onText(/\/bill/, async (msg) => {
|
|
|
+ const billMessage = await generateBillMessage(msg.chat.id);
|
|
|
+ sendMessage(msg.chat.id, billMessage, {
|
|
|
+ reply_markup: generateInlineKeyboard(msg.chat.id)
|
|
|
+ });
|
|
|
+});
|
|
|
|
|
|
-// 保存数据
|
|
|
-function saveData() {
|
|
|
- try {
|
|
|
- fs.writeFileSync(process.env.DB_FILE, JSON.stringify(data, null, 2));
|
|
|
- } catch (error) {
|
|
|
- console.error(formatLog('Error saving data', error));
|
|
|
- }
|
|
|
-}
|
|
|
+// - 3.帮助命令
|
|
|
+bot.onText(/\/help/, (msg) => {
|
|
|
+ const helpMessage = `
|
|
|
+🤖 <b>机器人使用指南</b>
|
|
|
|
|
|
-// 加载数据
|
|
|
-function loadData() {
|
|
|
- try {
|
|
|
- if (fs.existsSync(process.env.DB_FILE)) {
|
|
|
- const savedData = JSON.parse(fs.readFileSync(process.env.DB_FILE));
|
|
|
- data = {
|
|
|
- ...data,
|
|
|
- ...savedData
|
|
|
- };
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- console.error(formatLog('Error loading data', error));
|
|
|
- }
|
|
|
-}
|
|
|
+<b>📝 快捷命令</b>
|
|
|
+• <code>+数字</code> 快速记录入款
|
|
|
+• <code>-数字</code> 快速记录入款修正
|
|
|
+• <code>下发数字</code> 快速记录下发
|
|
|
+• <code>下发-数字</code> 快速记录下发修正
|
|
|
|
|
|
-// 测试数据库连接并初始化
|
|
|
-testConnection().then(() => {
|
|
|
- return initDatabase();
|
|
|
-}).then(() => {
|
|
|
- // 加载数据
|
|
|
- loadData();
|
|
|
+<b>⚙️ 设置命令</b>
|
|
|
+• <code>设置费率数字</code> 设置费率
|
|
|
+• <code>设置汇率数字</code> 设置汇率
|
|
|
+• <code>设置操作人@用户名</code> 设置群组操作人
|
|
|
|
|
|
- // 启动服务器
|
|
|
- const PORT = process.env.PORT || 3000;
|
|
|
- app.listen(PORT, () => {
|
|
|
- console.log(formatLog({
|
|
|
- PORT: PORT
|
|
|
- }));
|
|
|
- console.log('机器人已准备就绪!');
|
|
|
- });
|
|
|
-}).catch(error => {
|
|
|
- console.error(formatLog('启动失败', error));
|
|
|
- process.exit(1);
|
|
|
+<b>📊 查询命令</b>
|
|
|
+• <code>/bill</code> 查看当前账单
|
|
|
+• <code>/help</code> 显示此帮助信息
|
|
|
+
|
|
|
+<b>💡 使用提示</b>
|
|
|
+• 所有金额输入请使用数字
|
|
|
+• 账单信息实时更新
|
|
|
+• 如需帮助请联系管理员
|
|
|
+ `;
|
|
|
+ sendMessage(msg.chat.id, helpMessage);
|
|
|
});
|
|
|
|
|
|
-// 处理机器人被添加到群组
|
|
|
+// - 4.群组信息更新
|
|
|
+// 机器人被添加到群组
|
|
|
async function handleBotAdded(msg, chatId, chatType, chatIdStr, existingGroup) {
|
|
|
try {
|
|
|
// 获取群组链接
|
|
@@ -944,20 +814,6 @@ async function handleBotAdded(msg, chatId, chatType, chatIdStr, existingGroup) {
|
|
|
saveData();
|
|
|
}
|
|
|
|
|
|
- // 发送欢迎消息
|
|
|
- await bot.sendMessage(chatId, '感谢添加我为群组成员!使用 /help 查看可用命令。', {
|
|
|
- parse_mode: 'HTML'
|
|
|
- });
|
|
|
-
|
|
|
- // 发送账单消息
|
|
|
- const billMessage = await generateBillMessage(chatId);
|
|
|
- if (billMessage) {
|
|
|
- await bot.sendMessage(chatId, billMessage, {
|
|
|
- parse_mode: 'HTML',
|
|
|
- reply_markup: generateInlineKeyboard(chatId)
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
console.log(formatLog({
|
|
|
操作: '群组添加成功',
|
|
|
群组ID: chatIdStr,
|
|
@@ -993,7 +849,6 @@ async function handleBotAdded(msg, chatId, chatType, chatIdStr, existingGroup) {
|
|
|
await sendMessage(chatId, '添加群组失败,请联系管理员。');
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
// 处理群组信息更新
|
|
|
async function handleGroupUpdate(msg, chatId, chatType, chatIdStr, existingGroup, newStatus, newType) {
|
|
|
const connection = await pool.getConnection();
|
|
@@ -1151,7 +1006,6 @@ async function handleGroupUpdate(msg, chatId, chatType, chatIdStr, existingGroup
|
|
|
connection.release();
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
// 处理群组状态变更
|
|
|
bot.on('my_chat_member', async (msg) => {
|
|
|
try {
|
|
@@ -1259,6 +1113,81 @@ bot.on('my_chat_member', async (msg) => {
|
|
|
}));
|
|
|
}
|
|
|
});
|
|
|
+// 处理机器人被移出群组
|
|
|
+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));
|
|
|
+ }
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+// 保存数据
|
|
|
+function saveData() {
|
|
|
+ try {
|
|
|
+ fs.writeFileSync(process.env.DB_FILE, JSON.stringify(data, null, 2));
|
|
|
+ } catch (error) {
|
|
|
+ console.error(formatLog('Error saving data', error));
|
|
|
+ }
|
|
|
+}
|
|
|
+// 加载数据
|
|
|
+function loadData() {
|
|
|
+ try {
|
|
|
+ if (fs.existsSync(process.env.DB_FILE)) {
|
|
|
+ const savedData = JSON.parse(fs.readFileSync(process.env.DB_FILE));
|
|
|
+ data = {
|
|
|
+ ...data,
|
|
|
+ ...savedData
|
|
|
+ };
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error(formatLog('Error loading data', error));
|
|
|
+ }
|
|
|
+}
|
|
|
+// 测试数据库连接并初始化
|
|
|
+testConnection().then(() => {
|
|
|
+ return initDatabase();
|
|
|
+}).then(() => {
|
|
|
+ // 加载数据
|
|
|
+ loadData();
|
|
|
+
|
|
|
+ // 启动服务器
|
|
|
+ const PORT = process.env.PORT || 3000;
|
|
|
+ app.listen(PORT, () => {
|
|
|
+ console.log(formatLog({
|
|
|
+ PORT: PORT
|
|
|
+ }));
|
|
|
+ console.log('机器人已准备就绪!');
|
|
|
+ });
|
|
|
+}).catch(error => {
|
|
|
+ console.error(formatLog('启动失败', error));
|
|
|
+ process.exit(1);
|
|
|
+});
|
|
|
|
|
|
// 导入公共路由
|
|
|
const publicRoutes = require('./routes/public');
|