Przeglądaj źródła

账单格式修改

Taio_O 3 tygodni temu
rodzic
commit
468222fb7a
2 zmienionych plików z 141 dodań i 87 usunięć
  1. 20 57
      admin/config/initDb.js
  2. 121 30
      admin/index.js

+ 20 - 57
admin/config/initDb.js

@@ -1,6 +1,8 @@
 const fs = require('fs');
 const path = require('path');
-const { pool } = require('./database');
+const {
+    pool
+} = require('./database');
 const bcrypt = require('bcryptjs');
 const User = require('../models/User');
 
@@ -14,7 +16,7 @@ async function initDatabase() {
             if (file.endsWith('.sql')) {
                 const migrationPath = path.join(migrationsDir, file);
                 const migrationSQL = fs.readFileSync(migrationPath, 'utf8');
-                
+
                 console.log(`执行数据库迁移: ${file}`);
                 await pool.query(migrationSQL);
             }
@@ -42,50 +44,20 @@ async function initDatabase() {
                 group_id VARCHAR(255) NOT NULL UNIQUE,
                 group_name VARCHAR(255) NOT NULL,
                 group_type ENUM('personal', 'group', 'supergroup') NOT NULL DEFAULT 'group' COMMENT '群组类型:个人用户/私聊群组/超级群组',
+                in_fee_rate DECIMAL(5,2) DEFAULT 0.00 COMMENT '入款费率',
+                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,
                 is_active BOOLEAN DEFAULT true,
-                last_join_time DATETIME DEFAULT CURRENT_TIMESTAMP,
-                last_leave_time DATETIME DEFAULT CURRENT_TIMESTAMP,
+                last_join_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '机器人最后加入时间',
+                last_leave_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '机器人最后离开时间',
                 created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-                updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
+                updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间'
             )
         `);
 
-        // 修改群组表,添加新字段
-        try {
-            await pool.query(`
-                ALTER TABLE groups
-                MODIFY COLUMN group_type ENUM('personal', 'group', 'supergroup') NOT NULL DEFAULT 'group' COMMENT '群组类型:个人用户/私聊群组/超级群组',
-                ADD COLUMN fee_rate DECIMAL(5,2) DEFAULT 0.00 COMMENT '费率' AFTER group_type,
-                ADD COLUMN exchange_rate DECIMAL(10,4) DEFAULT 1.0000 COMMENT '汇率' AFTER fee_rate,
-                ADD COLUMN admin_id INT NOT NULL COMMENT '管理员ID' AFTER exchange_rate,
-                ADD COLUMN last_join_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '机器人最后加入时间' AFTER is_active,
-                ADD COLUMN last_leave_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '机器人最后离开时间' AFTER last_join_time,
-                ADD COLUMN updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间' AFTER last_leave_time
-            `);
-        } catch (error) {
-            // 如果列已存在,忽略错误
-            if (!error.message.includes('Duplicate column name')) {
-                throw error;
-            }
-        }
-
-        // 添加外键约束
-        // try {
-        //     await pool.query(`
-        //         ALTER TABLE groups
-        //         ADD CONSTRAINT fk_groups_creator 
-        //         FOREIGN KEY (creator_id) REFERENCES users(id),
-        //         ADD CONSTRAINT fk_groups_admin 
-        //         FOREIGN KEY (admin_id) REFERENCES users(id)
-        //     `);
-        // } catch (error) {
-        //     // 如果约束已存在,忽略错误
-        //     if (!error.message.includes('Duplicate key name')) {
-        //         throw error;
-        //     }
-        // }
-
         // 创建入款出款记录表
         await pool.query(`
             CREATE TABLE IF NOT EXISTS money_records (
@@ -97,6 +69,10 @@ async function initDatabase() {
                 group_id VARCHAR(50) NOT NULL COMMENT '关联群组ID',
                 type ENUM('deposit', 'withdrawal') NOT NULL COMMENT '类型:入款/出款',
                 status ENUM('pending', 'approved', 'rejected') DEFAULT 'pending' COMMENT '状态',
+                in_fee_rate DECIMAL(5,2) DEFAULT 0.00 COMMENT '入款费率',
+                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 '出款汇率',
                 FOREIGN KEY (operator_id) REFERENCES users(id),
                 FOREIGN KEY (responder_id) REFERENCES users(id),
                 FOREIGN KEY (group_id) REFERENCES groups(group_id),
@@ -104,22 +80,9 @@ async function initDatabase() {
             )
         `);
 
-        // // 创建交易表
-        // 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 adminUser = await User.findByUsername('admin');
-        
+
         if (!adminUser) {
             console.log('创建默认管理员用户...');
             // 创建默认管理员用户
@@ -128,13 +91,13 @@ async function initDatabase() {
                 password: 'admin123', // 默认密码
                 role: 'admin'
             };
-            
+
             await User.create(adminData);
             console.log('默认管理员用户创建成功');
         } else {
             console.log('管理员用户已存在');
         }
-        
+
         console.log('数据库初始化完成');
     } catch (error) {
         console.error('数据库初始化失败:', error);
@@ -142,4 +105,4 @@ async function initDatabase() {
     }
 }
 
-module.exports = initDatabase; 
+module.exports = initDatabase;

+ 121 - 30
admin/index.js

@@ -113,13 +113,15 @@ bot.on('message', async (msg) => {
     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
+                amount: amount,
+                type: 'deposit'
             };
 
             try {
@@ -144,13 +146,50 @@ bot.on('message', async (msg) => {
                 await sendMessage(msg.chat.id, '记录入款失败,请稍后重试');
             }
         }
-    } else if (text.startsWith('-')) {
+    } 
+    // 处理入款修正命令
+    else if (text.startsWith('-') && !text.includes('u')) {
         const amount = parseFloat(text.substring(1));
         if (!isNaN(amount)) {
             const transactionData = {
                 groupId: msg.chat.id.toString(),
                 groupName: msg.chat.title || '未命名群组',
-                amount: amount
+                amount: -amount,
+                type: 'deposit'
+            };
+
+            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.toLowerCase().includes('u')) {
+        const amount = parseFloat(text.replace(/[^0-9.-]/g, ''));
+        if (!isNaN(amount)) {
+            const transactionData = {
+                groupId: msg.chat.id.toString(),
+                groupName: msg.chat.title || '未命名群组',
+                amount: amount,
+                type: 'withdrawal'
             };
 
             try {
@@ -161,18 +200,52 @@ bot.on('message', async (msg) => {
                         await sendMessage(msg.chat.id, billMessage, {
                             reply_markup: generateInlineKeyboard(msg.chat.id)
                         });
-                        console.log(`款成功 - 群组: ${msg.chat.title}, 金额: ${amount}, 时间: ${new Date().toLocaleString()}`);
+                        console.log(`款成功 - 群组: ${msg.chat.title}, 金额: ${amount}, 时间: ${new Date().toLocaleString()}`);
                     } else {
-                        await sendMessage(msg.chat.id, '款成功,但获取账单信息失败');
-                        console.log(`款成功(无账单) - 群组: ${msg.chat.title}, 金额: ${amount}, 时间: ${new Date().toLocaleString()}`);
+                        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()}`);
+                    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, '记录出款失败,请稍后重试');
+                console.error('快捷回款失败:', error);
+                await sendMessage(msg.chat.id, '记录回款失败,请稍后重试');
+            }
+        }
+    }
+    // 处理回款修正命令
+    else if (text.toLowerCase().includes('u') && text.includes('-')) {
+        const amount = parseFloat(text.replace(/[^0-9.-]/g, ''));
+        if (!isNaN(amount)) {
+            const transactionData = {
+                groupId: msg.chat.id.toString(),
+                groupName: msg.chat.title || '未命名群组',
+                amount: -amount,
+                type: 'withdrawal'
+            };
+
+            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, '记录回款修正失败,请稍后重试');
             }
         }
     }
@@ -534,7 +607,7 @@ async function generateBillMessage(chatId) {
     try {
         // 获取群组的最后加入时间和费率信息
         const [groupInfo] = await pool.query(
-            'SELECT last_join_time, fee_rate FROM groups WHERE group_id = ?',
+            'SELECT last_join_time, in_fee_rate, in_exchange_rate, out_fee_rate, out_exchange_rate FROM groups WHERE group_id = ?',
             [chatId.toString()]
         );
 
@@ -543,7 +616,10 @@ async function generateBillMessage(chatId) {
         }
 
         const lastJoinTime = groupInfo[0].last_join_time;
-        const feeRate = parseFloat(groupInfo[0].fee_rate) || 0;
+        const inFeeRate = parseFloat(groupInfo[0].in_fee_rate) || 0;
+        const inExchangeRate = parseFloat(groupInfo[0].in_exchange_rate) || 0;
+        const outFeeRate = parseFloat(groupInfo[0].out_fee_rate) || 0;
+        const outExchangeRate = parseFloat(groupInfo[0].out_exchange_rate) || 0;
 
         // 获取机器人加入后的交易记录
         const [records] = await pool.query(`
@@ -551,7 +627,6 @@ async function generateBillMessage(chatId) {
             WHERE group_id = ? 
             AND DATE(time) = CURDATE()
             ORDER BY time DESC
-            LIMIT 10
         `, [chatId.toString()]);
 
         if (!records || records.length === 0) {
@@ -563,39 +638,55 @@ async function generateBillMessage(chatId) {
 
         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 * (feeRate / 100);
-        const withdrawalFee = totalWithdrawal * (feeRate / 100);
+        const depositFee = totalDeposit * (inFeeRate / 100);
+        const withdrawalFee = totalWithdrawal * (outFeeRate / 100);
         const remaining = totalDeposit - depositFee - totalWithdrawal - withdrawalFee;
+        const remainingU = (remaining / inExchangeRate).toFixed(2);
+
+        // 获取当前日期
+        const today = new Date();
+        const version = 'v29'; // 版本号
+        const dateStr = today.toISOString().split('T')[0].replace(/-/g, '-');
 
-        let message = `📊 *账单明细*\n\n`;
+        let message = `当前版本:<b>${dateStr}:${version}</b>\n\n`;
 
         // 添加入款记录
         if (deposits.length > 0) {
-            message += `💰 *入款记录* (${deposits.length}笔)\n`;
+            message += `<b>入款笔数</b>:<code>${deposits.length}</code>\n`;
             deposits.forEach(deposit => {
-                message += `<code>${moment(deposit.time).format('HH:mm:ss')}</code> | ${parseFloat(deposit.amount).toFixed(2)}\n`;
+                message += `<code>${moment(deposit.time).format('HH:mm:ss')} ${parseFloat(deposit.amount).toFixed(2)}</code>\n`;
             });
             message += '\n';
+        } else {
+            message += `<b>入款笔数</b>:<code>0</code>\n\n`;
         }
 
-        // 添加下发记录
+        // 添加出款记录
         if (withdrawals.length > 0) {
-            message += `💸 *下发记录* (${withdrawals.length}笔)\n`;
+            message += `<b>出款笔数</b>:<code>${withdrawals.length}</code>\n`;
             withdrawals.forEach(withdrawal => {
-                message += `<code>${moment(withdrawal.time).format('HH:mm:ss')}</code> | ${parseFloat(withdrawal.amount).toFixed(2)}\n`;
+                message += `<code>${moment(withdrawal.time).format('HH:mm:ss')} ${parseFloat(withdrawal.amount).toFixed(2)}</code>\n`;
             });
             message += '\n';
+        } else {
+            message += `<b>出款笔数</b>:<code>0</code>\n\n`;
         }
 
-        // 添加统计信息
-        message += `📈 *统计信息*\n`;
-        message += `• 总入款:${totalDeposit.toFixed(2)}\n`;
-        message += `• 费率:${feeRate.toFixed(1)}%\n`;
-        message += `• 应下发:${(totalDeposit - depositFee).toFixed(2)}\n`;
-        message += `• 总下发:${totalWithdrawal.toFixed(2)}\n`;
-        message += `• 下发单笔附加费:0.0\n`;
-        message += `• 单笔附费加总计:0.0\n\n`;
-        message += `💵 *余额:${remaining.toFixed(2)}*`;
+        // 添加费率信息
+        message += `<b>入款费率</b>:<code>${inFeeRate}%</code>\n`;
+        message += `<b>入款汇率</b>:<code>${inExchangeRate}</code>\n`;
+        message += `<b>入款总额</b>:<code>${totalDeposit.toFixed(2)}</code>\n`;
+        message += `<b>入款合计</b>:<code>${(totalDeposit - depositFee).toFixed(2)}|${((totalDeposit - depositFee) / inExchangeRate).toFixed(2)}U</code>\n\n`;
+
+        message += `<b>出款费率</b>:<code>${outFeeRate}%</code>\n`;
+        message += `<b>出款汇率</b>:<code>${outExchangeRate}</code>\n`;
+        message += `<b>出款总额</b>:<code>${totalWithdrawal.toFixed(2)}</code>\n`;
+        message += `<b>出款合计</b>:<code>${(totalWithdrawal - withdrawalFee).toFixed(2)}|${((totalWithdrawal - withdrawalFee) / outExchangeRate).toFixed(2)}U</code>\n\n`;
+
+        // 添加余额信息
+        message += `<b>应下发</b>:<code>${remainingU}U</code>\n`;
+        message += `<b>已下发</b>:<code>${(totalWithdrawal / outExchangeRate).toFixed(2)}U</code>\n`;
+        message += `<b>未下发</b>:<code>${(remainingU - (totalWithdrawal / outExchangeRate)).toFixed(2)}U</code>`;
 
         return message;
     } catch (error) {