Kaynağa Gözat

设置操作人

Taio_O 3 hafta önce
ebeveyn
işleme
0e9d29a20f

+ 1 - 1
admin/config/initDb.js

@@ -48,8 +48,8 @@ async function initDatabase() {
                 in_exchange_rate DECIMAL(10,4) DEFAULT 1.0000 COMMENT '入款汇率',
                 out_fee_rate DECIMAL(5,2) DEFAULT 0.00 COMMENT '出款费率',
                 out_exchange_rate DECIMAL(10,4) DEFAULT 1.0000 COMMENT '出款汇率',
-                admin_id INT NOT NULL COMMENT '管理员ID',
                 creator_id VARCHAR(255) NOT NULL,
+                operators JSON COMMENT '操作人列表,格式:[{"operator_id": "用户ID", "operator_username": "用户名", "added_by": "添加人ID", "added_at": "添加时间"}]',
                 is_active BOOLEAN DEFAULT true,
                 last_join_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '机器人最后加入时间',
                 last_leave_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '机器人最后离开时间',

+ 93 - 1
admin/controllers/groupController.js

@@ -125,10 +125,102 @@ const deleteGroup = async (req, res) => {
     }
 };
 
+// @desc    添加群组操作人
+// @route   POST /api/groups/:groupId/operators
+// @access  Private
+const addOperator = async (req, res) => {
+    try {
+        const { groupId } = req.params;
+        const { operator_id, operator_username } = req.body;
+        const added_by = req.user.id;
+
+        // 检查群组是否存在
+        const group = await Group.findByGroupId(groupId);
+        if (!group) {
+            return res.status(404).json({ message: '群组不存在' });
+        }
+
+        // 检查添加人是否是群组创建者或现有操作人
+        const isCreator = group.creator_id === added_by;
+        const isOperator = await Group.isOperator(groupId, added_by);
+
+        if (!isCreator && !isOperator) {
+            return res.status(403).json({ message: '没有权限添加操作人' });
+        }
+
+        // 添加操作人
+        await Group.addOperator(groupId, {
+            operator_id,
+            operator_username,
+            added_by
+        });
+
+        res.status(201).json({ message: '操作人添加成功' });
+    } catch (error) {
+        console.error('添加操作人失败:', error);
+        if (error.message === '该用户已经是操作人') {
+            return res.status(400).json({ message: error.message });
+        }
+        res.status(500).json({ message: '服务器错误' });
+    }
+};
+
+// @desc    获取群组操作人列表
+// @route   GET /api/groups/:groupId/operators
+// @access  Private
+const getOperators = async (req, res) => {
+    try {
+        const { groupId } = req.params;
+        const operators = await Group.getOperators(groupId);
+        res.json(operators);
+    } catch (error) {
+        console.error('获取操作人列表失败:', error);
+        res.status(500).json({ message: '服务器错误' });
+    }
+};
+
+// @desc    删除群组操作人
+// @route   DELETE /api/groups/:groupId/operators/:operatorId
+// @access  Private
+const removeOperator = async (req, res) => {
+    try {
+        const { groupId, operatorId } = req.params;
+        const userId = req.user.id;
+
+        // 检查群组是否存在
+        const group = await Group.findByGroupId(groupId);
+        if (!group) {
+            return res.status(404).json({ message: '群组不存在' });
+        }
+
+        // 检查操作人是否是群组创建者或现有操作人
+        const isCreator = group.creator_id === userId;
+        const isOperator = await Group.isOperator(groupId, userId);
+
+        if (!isCreator && !isOperator) {
+            return res.status(403).json({ message: '没有权限删除操作人' });
+        }
+
+        // 删除操作人
+        const success = await Group.removeOperator(groupId, operatorId);
+        if (!success) {
+            return res.status(404).json({ message: '操作人不存在' });
+        }
+
+        res.json({ message: '操作人删除成功' });
+    } catch (error) {
+        console.error('删除操作人失败:', error);
+        res.status(500).json({ message: '服务器错误' });
+    }
+};
+
 module.exports = {
     getGroups,
     getGroupById,
     createGroup,
     updateGroup,
-    deleteGroup
+    deleteGroup,
+    addOperator,
+    getOperators,
+    removeOperator
 }; 

+ 236 - 23
admin/index.js

@@ -74,6 +74,53 @@ function isAdmin(userId) {
     return process.env.ADMIN_IDS.split(',').includes(userId.toString());
 }
 
+// 检查用户是否有权限操作机器人
+async function checkUserPermission(chatId, userId) {
+    try {
+        const [group] = await pool.query(
+            'SELECT creator_id, COALESCE(operators, "[]") as operators FROM groups WHERE group_id = ?',
+            [chatId.toString()]
+        );
+
+        if (!group || !group[0]) {
+            console.log(`权限检查失败 - 群组不存在: ${chatId}`);
+            return false;
+        }
+
+        const groupInfo = group[0];
+        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) {
+                operators = JSON.parse(groupInfo.operators);
+                if (!Array.isArray(operators)) {
+                    operators = [];
+                }
+            }
+        } catch (e) {
+            console.error('解析操作人列表失败:', e);
+            operators = [];
+        }
+        
+        const isOperator = operators.some(op => {
+            const isOp = op.operator_id === userIdStr;
+            console.log(`检查操作人 - 操作人ID: ${op.operator_id}, 用户ID: ${userIdStr}, 是否匹配: ${isOp}`);
+            return isOp;
+        });
+        
+        console.log(`权限检查结果 - 用户ID: ${userIdStr}, 是否创建者: ${isCreator}, 是否操作人: ${isOperator}`);
+        
+        return isCreator || isOperator;
+    } catch (error) {
+        console.error('检查用户权限失败:', error);
+        return false;
+    }
+}
+
 // 处理消息发送
 async function sendMessage(chatId, text, options = {}) {
     try {
@@ -113,6 +160,16 @@ bot.on('message', async (msg) => {
     const text = msg.text?.trim();
     if (!text) return;
 
+    // 检查用户权限
+    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;
+    }
+
     // 处理入款命令
     if (text.startsWith('+')) {
         let amount, exchangeRate, feeRate;
@@ -365,6 +422,116 @@ bot.on('message', async (msg) => {
             await sendMessage(msg.chat.id, '汇率设置失败,请输入大于0的数字');
         }
     }
+    // 处理设置操作人命令
+    else if (text.startsWith('设置操作人')) {
+        try {
+            const groupId = msg.chat.id.toString();
+            const mentionedUser = msg.entities?.find(e => e.type === 'mention');
+            
+            if (!mentionedUser) {
+                // 如果没有@用户,回复原消息并提示设置用户名
+                await bot.sendMessage(msg.chat.id, '请设置您的Telegram用户名后再试', {
+                    reply_to_message_id: msg.message_id
+                });
+                return;
+            }
+
+            // 获取被@的用户名
+            const username = text.slice(mentionedUser.offset + 1, mentionedUser.offset + mentionedUser.length);
+            
+            // 获取群组信息
+            const [group] = await pool.query(
+                'SELECT creator_id, COALESCE(operators, "[]") as operators FROM groups WHERE group_id = ?',
+                [groupId]
+            );
+
+            if (!group || !group[0]) {
+                await sendMessage(msg.chat.id, '群组信息不存在');
+                return;
+            }
+
+            const groupInfo = group[0];
+            const userId = msg.from.id.toString();
+            
+            // 检查操作权限(群组创建者或现有操作人)
+            const isCreator = groupInfo.creator_id === userId;
+            let operators = [];
+            
+            try {
+                if (groupInfo.operators) {
+                    operators = JSON.parse(groupInfo.operators);
+                    if (!Array.isArray(operators)) {
+                        operators = [];
+                    }
+                }
+            } catch (e) {
+                console.error('解析操作人列表失败:', e);
+                operators = [];
+            }
+            
+            const isOperator = operators.some(op => op.operator_id === userId);
+
+            if (!isCreator && !isOperator) {
+                await sendMessage(msg.chat.id, '您没有权限设置操作人');
+                return;
+            }
+
+            // 获取被@用户的ID
+            const [user] = await pool.query(
+                'SELECT id FROM users WHERE username = ?',
+                [username]
+            );
+
+            let newOperatorId;
+            if (!user || !user[0]) {
+                // 如果用户不存在,创建新用户
+                try {
+                    const [result] = await pool.query(
+                        'INSERT INTO users (username, password, role) VALUES (?, ?, ?)',
+                        [username, '', 'user']
+                    );
+                    newOperatorId = result.insertId.toString();
+                    console.log(`创建新用户成功 - 用户名: ${username}, ID: ${newOperatorId}`);
+                } catch (error) {
+                    console.error('创建新用户失败:', error);
+                    await sendMessage(msg.chat.id, '创建用户失败,请稍后重试');
+                    return;
+                }
+            } else {
+                newOperatorId = user[0].id.toString();
+            }
+
+            // 检查是否已经是操作人
+            if (operators.some(op => op.operator_id === newOperatorId)) {
+                await sendMessage(msg.chat.id, '该用户已经是操作人');
+                return;
+            }
+
+            // 添加新操作人
+            operators.push({
+                operator_id: newOperatorId,
+                operator_username: username,
+                added_by: userId,
+                added_at: new Date().toISOString()
+            });
+
+            // 更新群组
+            await pool.query(
+                'UPDATE groups SET operators = ? WHERE group_id = ?',
+                [JSON.stringify(operators), groupId]
+            );
+
+            await sendMessage(msg.chat.id, `已成功设置 @${username} 为操作人`);
+            console.log(`设置操作人成功 - 群组: ${msg.chat.title}, 新操作人: ${username}, 设置者: ${msg.from.username || msg.from.first_name}, 时间: ${new Date().toLocaleString()}`);
+        } catch (error) {
+            console.error('设置操作人失败:', error);
+            if (error.code === 'ER_BAD_FIELD_ERROR') {
+                await sendMessage(msg.chat.id, '系统正在升级,请稍后再试');
+            } else {
+                await sendMessage(msg.chat.id, '设置操作人失败,请稍后重试');
+            }
+        }
+    }
     // 处理TRX地址
     else if (/^T[A-Za-z0-9]{33}$/.test(text)) {
         try {
@@ -497,11 +664,17 @@ bot.on('new_chat_members', async (msg) => {
                     console.log(formatLog(groupData));
 
                     try {
-                        // 直接使用 SQL 插入群组数据
+                        // 直接使用 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)
+                            (group_id, group_name, group_type, creator_id, is_active, last_join_time, 
+                             in_fee_rate, in_exchange_rate, out_fee_rate, out_exchange_rate, operators) 
+                            VALUES (?, ?, ?, ?, true, CURRENT_TIMESTAMP, 0.00, 1.0000, 0.00, 1.0000, '[]')
+                            ON DUPLICATE KEY UPDATE
+                            group_name = VALUES(group_name),
+                            group_type = VALUES(group_type),
+                            is_active = true,
+                            last_join_time = CURRENT_TIMESTAMP
                         `, [
                             groupData.groupId,
                             groupData.groupName,
@@ -888,42 +1061,75 @@ async function handleBotAdded(msg, chatId, chatType, chatIdStr, 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',
+                groupType: chatType === 'private' ? 'personal' : chatType,
                 creatorId: msg.from.id.toString()
             };
 
-            const id = await Group.create({
-                groupId: groupData.groupId,
-                groupName: groupData.groupName,
-                creatorId: groupData.creatorId
-            });
+            try {
+                // 直接使用 SQL 插入或更新群组数据
+                const [result] = await pool.query(`
+                    INSERT INTO groups 
+                    (group_id, group_name, group_type, creator_id, is_active, last_join_time, 
+                     in_fee_rate, in_exchange_rate, out_fee_rate, out_exchange_rate, operators) 
+                    VALUES (?, ?, ?, ?, true, CURRENT_TIMESTAMP, 0.00, 1.0000, 0.00, 1.0000, '[]')
+                    ON DUPLICATE KEY UPDATE
+                    group_name = VALUES(group_name),
+                    group_type = VALUES(group_type),
+                    is_active = true,
+                    last_join_time = CURRENT_TIMESTAMP
+                `, [
+                    groupData.groupId,
+                    groupData.groupName,
+                    groupData.groupType,
+                    groupData.creatorId
+                ]);
 
-            if (id) {
                 // 更新内存中的群组列表
                 if (!data.allowedGroups.includes(chatIdStr)) {
                     data.allowedGroups.push(chatIdStr);
                     saveData();
+                    console.log(`群组已添加 - ID: ${chatIdStr}, 名称: ${groupData.groupName}`);
+                }
+
+                try {
+                    // 发送欢迎消息
+                    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)
+                        });
+                    }
+                } catch (messageError) {
+                    console.error('发送消息失败:', messageError.message);
+                }
+            } catch (error) {
+                console.error('创建群组失败:', {
+                    错误: error.message,
+                    群组ID: groupData.groupId
+                });
+                try {
+                    await bot.sendMessage(chatId, '添加群组失败,请联系管理员。', {
+                        parse_mode: 'HTML'
+                    });
+                } catch (messageError) {
+                    console.error('发送错误消息失败:', messageError.message);
                 }
-                console.log('机器人首次被添加到群组');
-                console.log(formatLog(groupInfo));
-                await sendMessage(chatId, '感谢添加我为群组成员!使用 /help 查看可用命令。');
-            } else {
-                await sendMessage(chatId, '添加群组失败,请联系管理员。');
             }
         }
     } catch (error) {
-        console.error(formatLog({
-            错误: '处理机器人首次加入群组失败',
-            详情: error.message
-        }));
+        console.error('处理群组添加失败:', error.message);
         await sendMessage(chatId, '添加群组失败,请联系管理员。');
     }
 }
@@ -1116,12 +1322,19 @@ bot.on('my_chat_member', async (msg) => {
             chatType === 'supergroup' ? 'supergroup' : 'group';
             
         // 如果是机器人首次被添加到群组(从非成员变为成员)
-        if (oldStatus === 'left' && newStatus === 'member' && existingGroup.group_type != newType) {
-            await handleBotAdded(msg, chatId, chatType, chatIdStr, existingGroup);
+        if (oldStatus === 'left' && newStatus === 'member') {
+            if (!existingGroup) {
+                await handleBotAdded(msg, chatId, chatType, chatIdStr, null);
+            } else if (existingGroup.group_type !== newType) {
+                await handleBotAdded(msg, chatId, chatType, chatIdStr, existingGroup);
+            }
         }
 
         if (existingGroup) {
             await handleGroupUpdate(msg, chatId, chatType, chatIdStr, existingGroup, newStatus);
+        } else if (newStatus === 'member') {
+            // 如果是新群组且机器人被添加为成员
+            await handleBotAdded(msg, chatId, chatType, chatIdStr, null);
         }
     } catch (error) {
         console.error(formatLog({

+ 118 - 0
admin/models/Group.js

@@ -155,6 +155,124 @@ const Group = {
             console.error('删除群组失败:', error);
             throw error;
         }
+    },
+
+    // 添加操作人
+    addOperator: async (groupId, { operator_id, operator_username, added_by }) => {
+        try {
+            // 获取当前群组信息
+            const [group] = await pool.query(
+                'SELECT operators FROM groups WHERE group_id = ?',
+                [groupId]
+            );
+
+            if (!group[0]) {
+                throw new Error('群组不存在');
+            }
+
+            // 解析现有的操作人列表,如果为null则初始化为空数组
+            const operators = group[0].operators ? JSON.parse(group[0].operators) : [];
+
+            // 检查操作人是否已存在
+            if (operators.some(op => op.operator_id === operator_id)) {
+                throw new Error('该用户已经是操作人');
+            }
+
+            // 添加新操作人
+            operators.push({
+                operator_id,
+                operator_username,
+                added_by,
+                added_at: new Date().toISOString()
+            });
+
+            // 更新群组
+            await pool.query(
+                'UPDATE groups SET operators = ? WHERE group_id = ?',
+                [JSON.stringify(operators), groupId]
+            );
+
+            return true;
+        } catch (error) {
+            console.error('添加操作人失败:', error);
+            throw error;
+        }
+    },
+
+    // 检查用户是否是操作人
+    isOperator: async (groupId, operatorId) => {
+        try {
+            const [group] = await pool.query(
+                'SELECT operators FROM groups WHERE group_id = ?',
+                [groupId]
+            );
+
+            if (!group[0] || !group[0].operators) {
+                return false;
+            }
+
+            const operators = JSON.parse(group[0].operators);
+            return operators.some(op => op.operator_id === operatorId);
+        } catch (error) {
+            console.error('检查操作人状态失败:', error);
+            throw error;
+        }
+    },
+
+    // 获取群组的所有操作人
+    getOperators: async (groupId) => {
+        try {
+            const [group] = await pool.query(
+                'SELECT operators FROM groups WHERE group_id = ?',
+                [groupId]
+            );
+
+            if (!group[0] || !group[0].operators) {
+                return [];
+            }
+
+            return JSON.parse(group[0].operators);
+        } catch (error) {
+            console.error('获取群组操作人列表失败:', error);
+            throw error;
+        }
+    },
+
+    // 删除操作人
+    removeOperator: async (groupId, operatorId) => {
+        try {
+            // 获取当前群组信息
+            const [group] = await pool.query(
+                'SELECT operators FROM groups WHERE group_id = ?',
+                [groupId]
+            );
+
+            if (!group[0] || !group[0].operators) {
+                throw new Error('群组不存在或没有操作人');
+            }
+
+            // 解析现有的操作人列表
+            const operators = JSON.parse(group[0].operators);
+
+            // 过滤掉要删除的操作人
+            const updatedOperators = operators.filter(op => op.operator_id !== operatorId);
+
+            // 如果操作人列表没有变化,说明要删除的操作人不存在
+            if (operators.length === updatedOperators.length) {
+                return false;
+            }
+
+            // 更新群组
+            await pool.query(
+                'UPDATE groups SET operators = ? WHERE group_id = ?',
+                [JSON.stringify(updatedOperators), groupId]
+            );
+
+            return true;
+        } catch (error) {
+            console.error('删除操作人失败:', error);
+            throw error;
+        }
     }
 };
 

+ 4 - 1
admin/数据文件路径

@@ -44,6 +44,9 @@
     "-4719273162",
     "-1002602451051",
     "-1002249794545",
-    "-1002676340401"
+    "-1002676340401",
+    "-4750899185",
+    "-4779509671",
+    "-4666274251"
   ]
 }