Taio_O il y a 1 mois
Parent
commit
406cec562d
4 fichiers modifiés avec 392 ajouts et 86 suppressions
  1. 12 12
      admin/config/initDb.js
  2. 217 70
      admin/index.js
  3. 147 0
      admin/models/Transaction.js
  4. 16 4
      admin/数据文件路径

+ 12 - 12
admin/config/initDb.js

@@ -81,18 +81,18 @@ const initDatabase = async () => {
             )
         `);
 
-        // 创建交易表
-        await pool.query(`
-            CREATE TABLE IF NOT EXISTS transactions (
-                id INT AUTO_INCREMENT PRIMARY KEY,
-                group_id VARCHAR(50) NOT NULL,
-                group_name VARCHAR(100) NOT NULL,
-                type ENUM('deposit', 'withdrawal') NOT NULL,
-                amount DECIMAL(10,2) NOT NULL,
-                time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
-                INDEX idx_group_time (group_id, time)
-            )
-        `);
+        // // 创建交易表
+        // await pool.query(`
+        //     CREATE TABLE IF NOT EXISTS transactions (
+        //         id INT AUTO_INCREMENT PRIMARY KEY,
+        //         group_id VARCHAR(50) NOT NULL,
+        //         group_name VARCHAR(100) NOT NULL,
+        //         type ENUM('deposit', 'withdrawal') NOT NULL,
+        //         amount DECIMAL(10,2) NOT NULL,
+        //         time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+        //         INDEX idx_group_time (group_id, time)
+        //     )
+        // `);
 
         // 创建默认管理员账户
         const adminPassword = await bcrypt.hash('admin123', 10);

+ 217 - 70
admin/index.js

@@ -8,6 +8,7 @@ const moment = require('moment');
 const { pool, testConnection } = require('./config/database');
 const initDatabase = require('./config/initDb');
 const Group = require('./models/Group');
+const Transaction = require('./models/Transaction');
 
 const app = express();
 
@@ -51,6 +52,15 @@ function isAdmin(userId) {
 // 处理消息发送
 async function sendMessage(chatId, text, options = {}) {
     try {
+        // 如果包含内联键盘,验证URL
+        if (options.reply_markup && options.reply_markup.inline_keyboard) {
+            const keyboard = generateInlineKeyboard(chatId);
+            if (!keyboard) {
+                // 如果键盘无效,发送不带键盘的消息
+                return await bot.sendMessage(chatId, text);
+            }
+            options.reply_markup = keyboard;
+        }
         return await bot.sendMessage(chatId, text, options);
     } catch (error) {
         console.error('发送消息失败:', error);
@@ -66,17 +76,76 @@ async function sendMessage(chatId, text, options = {}) {
     }
 }
 
-// 处理所有消息
-bot.on('message', (msg) => {
-    console.log('收到消息:', {
-        chatId: msg.chat.id,
-        chatType: msg.chat.type,
-        chatTitle: msg.chat.title,
-        fromId: msg.from.id,
-        fromUsername: msg.from.username,
-        text: msg.text,
-        date: new Date(msg.date * 1000).toLocaleString()
-    });
+// 处理快捷命令
+bot.on('message', async (msg) => {
+    if (!isGroupAllowed(msg.chat.id)) return;
+
+    const text = msg.text?.trim();
+    if (!text) return;
+
+    if (text.startsWith('+')) {
+        const amount = parseFloat(text.substring(1));
+        if (!isNaN(amount)) {
+            const transactionData = {
+                groupId: msg.chat.id.toString(),
+                groupName: msg.chat.title || '未命名群组',
+                amount: amount
+            };
+
+            try {
+                const result = await Transaction.deposit(transactionData);
+                if (result.success) {
+                    const billMessage = await generateBillMessage(msg.chat.id);
+                    if (billMessage) {
+                        await sendMessage(msg.chat.id, billMessage, {
+                            reply_markup: generateInlineKeyboard(msg.chat.id)
+                        });
+                        console.log(`入款成功 - 群组: ${msg.chat.title}, 金额: ${amount}, 时间: ${new Date().toLocaleString()}`);
+                    } else {
+                        await sendMessage(msg.chat.id, '入款成功,但获取账单信息失败');
+                        console.log(`入款成功(无账单) - 群组: ${msg.chat.title}, 金额: ${amount}, 时间: ${new Date().toLocaleString()}`);
+                    }
+                } else {
+                    await sendMessage(msg.chat.id, result.message || '入款失败');
+                    console.log(`入款失败 - 群组: ${msg.chat.title}, 金额: ${amount}, 原因: ${result.message}, 时间: ${new Date().toLocaleString()}`);
+                }
+            } catch (error) {
+                console.error('快捷入款失败:', error);
+                await sendMessage(msg.chat.id, '记录入款失败,请稍后重试');
+            }
+        }
+    } else if (text.startsWith('-')) {
+        const amount = parseFloat(text.substring(1));
+        if (!isNaN(amount)) {
+            const transactionData = {
+                groupId: msg.chat.id.toString(),
+                groupName: msg.chat.title || '未命名群组',
+                amount: amount
+            };
+
+            try {
+                const result = await Transaction.withdrawal(transactionData);
+                if (result.success) {
+                    const billMessage = await generateBillMessage(msg.chat.id);
+                    if (billMessage) {
+                        await sendMessage(msg.chat.id, billMessage, {
+                            reply_markup: generateInlineKeyboard(msg.chat.id)
+                        });
+                        console.log(`出款成功 - 群组: ${msg.chat.title}, 金额: ${amount}, 时间: ${new Date().toLocaleString()}`);
+                    } else {
+                        await sendMessage(msg.chat.id, '出款成功,但获取账单信息失败');
+                        console.log(`出款成功(无账单) - 群组: ${msg.chat.title}, 金额: ${amount}, 时间: ${new Date().toLocaleString()}`);
+                    }
+                } else {
+                    await sendMessage(msg.chat.id, result.message || '出款失败');
+                    console.log(`出款失败 - 群组: ${msg.chat.title}, 金额: ${amount}, 原因: ${result.message}, 时间: ${new Date().toLocaleString()}`);
+                }
+            } catch (error) {
+                console.error('快捷出款失败:', error);
+                await sendMessage(msg.chat.id, '记录出款失败,请稍后重试');
+            }
+        }
+    }
 });
 
 // 处理新成员加入
@@ -93,7 +162,6 @@ bot.on('new_chat_members', async (msg) => {
             const chatIdStr = chatId.toString();
             if (!data.allowedGroups.includes(chatIdStr)) {
                 try {
-                    // 使用 createGroup 创建新群组
                     const groupData = {
                         groupId: chatIdStr,
                         groupName: msg.chat.title || '未命名群组',
@@ -223,49 +291,82 @@ bot.onText(/\/listgroups/, async (msg) => {
 });
 
 // 处理入款命令
-bot.onText(/\/deposit (.+)/, (msg, match) => {
+bot.onText(/\/deposit (.+)/, async (msg, match) => {
+    if (!isGroupAllowed(msg.chat.id)) {
+        sendMessage(msg.chat.id, '该群组未授权使用此功能');
+        return;
+    }
+
     const amount = parseFloat(match[1]);
     if (isNaN(amount)) {
         sendMessage(msg.chat.id, '请输入有效的金额');
         return;
     }
 
-    data.deposits.push({
-        time: new Date(),
-        amount: amount
-    });
-    data.lastUpdate = new Date();
-    saveData();
+    try {
+        const transactionData = {
+            groupId: msg.chat.id.toString(),
+            groupName: msg.chat.title || '未命名群组',
+            amount: amount
+        };
 
-    sendMessage(msg.chat.id, generateBillMessage(), {
-        reply_markup: generateInlineKeyboard()
-    });
+        const result = await Transaction.deposit(transactionData);
+        
+        if (result.success) {
+            sendMessage(msg.chat.id, generateBillMessage(msg.chat.id), {
+                reply_markup: generateInlineKeyboard(msg.chat.id)
+            });
+            console.log('机器人已准备就绪!');
+        } else {
+            sendMessage(msg.chat.id, result.message);
+            console.log('机器人已准备就绪!');
+        }
+    } catch (error) {
+        console.error('记录入款失败:', error);
+        sendMessage(msg.chat.id, '记录入款失败,请稍后重试');
+    }
 });
 
 // 处理下发命令
-bot.onText(/\/withdraw (.+)/, (msg, match) => {
+bot.onText(/\/withdraw (.+)/, async (msg, match) => {
+    if (!isGroupAllowed(msg.chat.id)) {
+        sendMessage(msg.chat.id, '该群组未授权使用此功能');
+        return;
+    }
+
     const amount = parseFloat(match[1]);
     if (isNaN(amount)) {
         sendMessage(msg.chat.id, '请输入有效的金额');
         return;
     }
 
-    data.withdrawals.push({
-        time: new Date(),
-        amount: amount
-    });
-    data.lastUpdate = new Date();
-    saveData();
+    try {
+        const transactionData = {
+            groupId: msg.chat.id.toString(),
+            groupName: msg.chat.title || '未命名群组',
+            amount: amount
+        };
 
-    sendMessage(msg.chat.id, generateBillMessage(), {
-        reply_markup: generateInlineKeyboard()
-    });
+        const result = await Transaction.withdrawal(transactionData);
+        
+        if (result.success) {
+            sendMessage(msg.chat.id, generateBillMessage(msg.chat.id), {
+                reply_markup: generateInlineKeyboard(msg.chat.id)
+            });
+        } else {
+            sendMessage(msg.chat.id, result.message);
+        }
+    } catch (error) {
+        console.error('记录下发失败:', error);
+        sendMessage(msg.chat.id, '记录下发失败,请稍后重试');
+    }
 });
 
 // 处理查看账单命令
-bot.onText(/\/bill/, (msg) => {
-    sendMessage(msg.chat.id, generateBillMessage(), {
-        reply_markup: generateInlineKeyboard()
+bot.onText(/\/bill/, async (msg) => {
+    const billMessage = await generateBillMessage(msg.chat.id);
+    sendMessage(msg.chat.id, billMessage, {
+        reply_markup: generateInlineKeyboard(msg.chat.id)
     });
 });
 
@@ -278,6 +379,10 @@ bot.onText(/\/help/, (msg) => {
 /bill - 查看当前账单
 /help - 显示此帮助信息
 
+快捷命令:
++<金额> - 快速记录入款(例如:+2000)
+-<金额> - 快速记录下发(例如:-2000)
+
 管理员命令:
 /addgroup <群组ID> - 添加允许的群组
 /removegroup <群组ID> - 移除允许的群组
@@ -287,63 +392,105 @@ bot.onText(/\/help/, (msg) => {
 });
 
 // 生成账单消息
-function generateBillMessage() {
-    const now = moment();
-    const deposits = data.deposits || [];
-    const withdrawals = data.withdrawals || [];
-    
-    const totalDeposit = deposits.reduce((sum, d) => sum + d.amount, 0);
-    const totalWithdrawal = withdrawals.reduce((sum, w) => sum + w.amount, 0);
-    const depositFee = totalDeposit * process.env.DEPOSIT_FEE_RATE;
-    const withdrawalFee = totalWithdrawal * process.env.WITHDRAWAL_FEE_RATE;
-    const remaining = totalDeposit - depositFee - totalWithdrawal - withdrawalFee;
+async function generateBillMessage(chatId) {
+    try {
+        // 获取最近的交易记录
+        const [records] = await pool.query(`
+            SELECT * FROM transactions 
+            WHERE group_id = ? 
+            ORDER BY time DESC
+            LIMIT 10
+        `, [chatId.toString()]);
+
+        if (!records || records.length === 0) {
+            return '暂无交易记录';
+        }
 
-    let message = `入款(${deposits.length})笔:\n`;
-    
-    // 添加入款记录
-    deposits.forEach(deposit => {
-        message += `${moment(deposit.time).format('HH:mm:ss')} ${deposit.amount.toFixed(2)}\n`;
-    });
+        const deposits = records.filter(r => r.type === 'deposit');
+        const withdrawals = records.filter(r => r.type === 'withdrawal');
+        
+        const totalDeposit = deposits.reduce((sum, d) => sum + parseFloat(d.amount), 0);
+        const totalWithdrawal = withdrawals.reduce((sum, w) => sum + parseFloat(w.amount), 0);
+        const depositFee = totalDeposit * (process.env.DEPOSIT_FEE_RATE || 0);
+        const withdrawalFee = totalWithdrawal * (process.env.WITHDRAWAL_FEE_RATE || 0);
+        const remaining = totalDeposit - depositFee - totalWithdrawal - withdrawalFee;
 
-    message += `\n下发(${withdrawals.length})笔:\n`;
-    
-    // 添加下发记录
-    withdrawals.forEach(withdrawal => {
-        message += `${moment(withdrawal.time).format('HH:mm:ss')} ${withdrawal.amount.toFixed(2)}\n`;
-    });
+        let message = `入款(${deposits.length})笔:\n`;
+        
+        // 添加入款记录
+        deposits.forEach(deposit => {
+            message += `${moment(deposit.time).format('HH:mm:ss')} ${parseFloat(deposit.amount).toFixed(2)}\n`;
+        });
+
+        message += `\n下发(${withdrawals.length})笔:\n`;
+        
+        // 添加下发记录
+        withdrawals.forEach(withdrawal => {
+            message += `${moment(withdrawal.time).format('HH:mm:ss')} ${parseFloat(withdrawal.amount).toFixed(2)}\n`;
+        });
 
-    message += `\n总入款:${totalDeposit.toFixed(2)}\n`;
-    message += `入款费率:${(process.env.DEPOSIT_FEE_RATE * 100).toFixed(1)}%\n`;
-    message += `下发费率:${(process.env.WITHDRAWAL_FEE_RATE * 100).toFixed(1)}%\n`;
-    message += `应下发:${(totalDeposit - depositFee).toFixed(2)}\n`;
-    message += `总下发:${totalWithdrawal.toFixed(2)}\n`;
-    message += `下发单笔附加费:0.0\n`;
-    message += `单笔附费加总计:0.0\n`;
-    message += `余:${remaining.toFixed(2)}`;
+        message += `\n总入款:${totalDeposit.toFixed(2)}\n`;
+        message += `入款费率:${((process.env.DEPOSIT_FEE_RATE || 0) * 100).toFixed(1)}%\n`;
+        message += `下发费率:${((process.env.WITHDRAWAL_FEE_RATE || 0) * 100).toFixed(1)}%\n`;
+        message += `应下发:${(totalDeposit - depositFee).toFixed(2)}\n`;
+        message += `总下发:${totalWithdrawal.toFixed(2)}\n`;
+        message += `下发单笔附加费:0.0\n`;
+        message += `单笔附费加总计:0.0\n`;
+        message += `余:${remaining.toFixed(2)}`;
 
-    return message;
+        return message;
+    } catch (error) {
+        console.error('生成账单消息失败:', error);
+        return '获取账单信息失败,请稍后重试';
+    }
 }
 
 // 生成内联键盘
-function generateInlineKeyboard() {
-    return {
+function generateInlineKeyboard(chatId) {
+    const keyboard = {
         inline_keyboard: [
             [
                 {
                     text: '点击跳转完整账单',
-                    url: `${process.env.BILL_PAGE_BASE_URL}?groupId=${data.allowedGroups[0]}`
+                    callback_data: `bill_page_${chatId}`
                 }
             ],
             [
                 {
                     text: '24小时商务对接',
-                    url: process.env.BUSINESS_ACCOUNT_URL
+                    callback_data: 'business_contact'
                 }
             ]
         ]
     };
+    return keyboard;
 }
 
+// 处理内联按钮回调
+bot.on('callback_query', async (callbackQuery) => {
+    const chatId = callbackQuery.message.chat.id;
+    const data = callbackQuery.data;
+
+    try {
+        if (data.startsWith('bill_page_')) {
+            const groupId = data.split('_')[2];
+            await bot.answerCallbackQuery(callbackQuery.id, {
+                url: `${process.env.BILL_PAGE_BASE_URL}?groupId=${groupId}`
+            });
+        } else if (data === 'business_contact') {
+            await bot.answerCallbackQuery(callbackQuery.id, {
+                url: 'https://t.me/your_business_account'
+            });
+        }
+    } catch (error) {
+        console.error('处理内联按钮回调失败:', error);
+        await bot.answerCallbackQuery(callbackQuery.id, {
+            text: '操作失败,请稍后重试',
+            show_alert: true
+        });
+    }
+});
+
 // 保存数据
 function saveData() {
     try {

+ 147 - 0
admin/models/Transaction.js

@@ -121,6 +121,153 @@ const Transaction = {
             recentTransactions,
             activeGroups
         };
+    },
+
+    // 入款方法
+    deposit: async (transactionData) => {
+        try {
+            const id = await Transaction.create({
+                groupId: transactionData.groupId,
+                groupName: transactionData.groupName,
+                type: 'deposit',
+                amount: parseFloat(transactionData.amount)
+            });
+
+            const transaction = await Transaction.findById(id);
+            if (transaction) {
+                return {
+                    success: true,
+                    transaction,
+                    message: '入款记录创建成功'
+                };
+            } else {
+                return {
+                    success: false,
+                    message: '入款记录创建失败'
+                };
+            }
+        } catch (error) {
+            console.error('入款记录创建失败:', error);
+            return {
+                success: false,
+                message: '入款记录创建失败,请稍后重试'
+            };
+        }
+    },
+
+    // 出款方法
+    withdrawal: async (transactionData) => {
+        try {
+            const id = await Transaction.create({
+                groupId: transactionData.groupId,
+                groupName: transactionData.groupName,
+                type: 'withdrawal',
+                amount: parseFloat(transactionData.amount)
+            });
+
+            const transaction = await Transaction.findById(id);
+            if (transaction) {
+                return {
+                    success: true,
+                    transaction,
+                    message: '出款记录创建成功'
+                };
+            } else {
+                return {
+                    success: false,
+                    message: '出款记录创建失败'
+                };
+            }
+        } catch (error) {
+            console.error('出款记录创建失败:', error);
+            return {
+                success: false,
+                message: '出款记录创建失败,请稍后重试'
+            };
+        }
+    },
+
+    // 查询群组账单
+    getGroupTransactions: async (groupId, options = {}) => {
+        const {
+            startDate,
+            endDate,
+            type,
+            page = 1,
+            limit = 10
+        } = options;
+
+        let sql = `
+            SELECT 
+                t.*,
+                DATE_FORMAT(t.time, '%Y-%m-%d %H:%i:%s') as formatted_time
+            FROM transactions t 
+            WHERE t.group_id = ?
+        `;
+        const params = [groupId];
+
+        if (startDate) {
+            sql += ' AND t.time >= ?';
+            params.push(startDate);
+        }
+        if (endDate) {
+            sql += ' AND t.time <= ?';
+            params.push(endDate);
+        }
+        if (type) {
+            sql += ' AND t.type = ?';
+            params.push(type);
+        }
+
+        // 获取总数
+        const [countResult] = await pool.query(
+            sql.replace('SELECT t.*, DATE_FORMAT(t.time, \'%Y-%m-%d %H:%i:%s\') as formatted_time', 'SELECT COUNT(*) as total'),
+            params
+        );
+        const total = countResult[0].total;
+
+        // 获取分页数据
+        sql += ' ORDER BY t.time DESC LIMIT ? OFFSET ?';
+        params.push(limit, (page - 1) * limit);
+
+        const [rows] = await pool.query(sql, params);
+
+        // 计算总入款和总出款
+        const [summary] = await pool.query(`
+            SELECT 
+                SUM(CASE WHEN type = 'deposit' THEN amount ELSE 0 END) as total_deposit,
+                SUM(CASE WHEN type = 'withdrawal' THEN amount ELSE 0 END) as total_withdrawal
+            FROM transactions 
+            WHERE group_id = ?
+            ${startDate ? 'AND time >= ?' : ''}
+            ${endDate ? 'AND time <= ?' : ''}
+        `, [groupId, ...(startDate ? [startDate] : []), ...(endDate ? [endDate] : [])]);
+
+        return {
+            transactions: rows,
+            total,
+            page: parseInt(page),
+            pages: Math.ceil(total / limit),
+            summary: {
+                totalDeposit: summary[0].total_deposit || 0,
+                totalWithdrawal: summary[0].total_withdrawal || 0,
+                balance: (summary[0].total_deposit || 0) - (summary[0].total_withdrawal || 0)
+            }
+        };
+    },
+
+    // 根据ID查找交易记录
+    findById: async (id) => {
+        try {
+            const [rows] = await pool.query(
+                'SELECT * FROM transactions WHERE id = ?',
+                [id]
+            );
+            return rows[0] || null;
+        } catch (error) {
+            console.error('查询交易记录失败:', error);
+            return null;
+        }
     }
 };
 

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

@@ -1,9 +1,21 @@
 {
-  "deposits": [],
+  "deposits": [
+    {
+      "time": "2025-05-07T02:54:47.356Z",
+      "amount": 200
+    },
+    {
+      "time": "2025-05-07T02:56:20.541Z",
+      "amount": 100
+    },
+    {
+      "time": "2025-05-07T03:00:11.021Z",
+      "amount": 200
+    }
+  ],
   "withdrawals": [],
-  "lastUpdate": null,
+  "lastUpdate": "2025-05-07T03:00:11.021Z",
   "allowedGroups": [
-    "4754375683",
-    "-4757139029"
+    "4754375683"
   ]
 }