|
@@ -3,75 +3,153 @@ const { pool } = require('../config/database');
|
|
|
// 创建交易表
|
|
|
const createTransactionTable = async () => {
|
|
|
try {
|
|
|
- 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 [tables] = await pool.query('SHOW TABLES LIKE "transactions"');
|
|
|
+ if (tables.length === 0) {
|
|
|
+ // 如果表不存在,创建新表
|
|
|
+ await pool.query(`
|
|
|
+ CREATE TABLE 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 COMMENT 'deposit:入款,withdrawal:出款',
|
|
|
+ amount DECIMAL(10,2) NOT NULL,
|
|
|
+ time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ remark VARCHAR(255) DEFAULT NULL COMMENT '备注',
|
|
|
+ operator_id INT NOT NULL COMMENT '操作人ID',
|
|
|
+ INDEX idx_group_time (group_id, time),
|
|
|
+ FOREIGN KEY (operator_id) REFERENCES users(id)
|
|
|
+ )
|
|
|
+ `);
|
|
|
+ console.log('交易表创建成功');
|
|
|
+ } else {
|
|
|
+ // 如果表存在,检查是否需要添加新字段
|
|
|
+ const [columns] = await pool.query('SHOW COLUMNS FROM transactions');
|
|
|
+ const columnNames = columns.map(col => col.Field);
|
|
|
+
|
|
|
+ // 检查并添加缺失的字段
|
|
|
+ if (!columnNames.includes('operator_id')) {
|
|
|
+ try {
|
|
|
+ // 先添加字段
|
|
|
+ await pool.query(`
|
|
|
+ ALTER TABLE transactions
|
|
|
+ ADD COLUMN operator_id INT NOT NULL DEFAULT 1 COMMENT '操作人ID' AFTER remark
|
|
|
+ `);
|
|
|
+ console.log('添加operator_id字段成功');
|
|
|
+
|
|
|
+ // 然后添加外键约束
|
|
|
+ await pool.query(`
|
|
|
+ ALTER TABLE transactions
|
|
|
+ ADD CONSTRAINT fk_transaction_operator
|
|
|
+ FOREIGN KEY (operator_id) REFERENCES users(id)
|
|
|
+ `);
|
|
|
+ console.log('添加外键约束成功');
|
|
|
+ } catch (error) {
|
|
|
+ console.error('添加operator_id字段或外键约束失败:', error);
|
|
|
+ // 如果添加外键失败,至少保留字段
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!columnNames.includes('remark')) {
|
|
|
+ await pool.query(`
|
|
|
+ ALTER TABLE transactions
|
|
|
+ ADD COLUMN remark VARCHAR(255) DEFAULT NULL COMMENT '备注' AFTER time
|
|
|
+ `);
|
|
|
+ console.log('添加remark字段成功');
|
|
|
+ }
|
|
|
+ }
|
|
|
} catch (error) {
|
|
|
- console.error('创建交易表失败:', error);
|
|
|
+ console.error('创建/更新交易表失败:', error);
|
|
|
+ throw error;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 初始化表
|
|
|
-createTransactionTable();
|
|
|
+createTransactionTable().catch(error => {
|
|
|
+ console.error('初始化交易表失败:', error);
|
|
|
+});
|
|
|
|
|
|
// 交易相关方法
|
|
|
const Transaction = {
|
|
|
// 获取交易列表
|
|
|
findAll: async (query = {}, page = 1, limit = 10) => {
|
|
|
- let sql = 'SELECT * FROM transactions WHERE 1=1';
|
|
|
- const params = [];
|
|
|
+ try {
|
|
|
+ console.log('查询参数:', query);
|
|
|
+ let sql = `
|
|
|
+ SELECT
|
|
|
+ t.*,
|
|
|
+ u.username as operator_name
|
|
|
+ FROM transactions t
|
|
|
+ LEFT JOIN users u ON t.operator_id = u.id
|
|
|
+ WHERE 1=1
|
|
|
+ `;
|
|
|
+ const params = [];
|
|
|
|
|
|
- if (query.startDate) {
|
|
|
- sql += ' AND time >= ?';
|
|
|
- params.push(query.startDate);
|
|
|
- }
|
|
|
- if (query.endDate) {
|
|
|
- sql += ' AND time <= ?';
|
|
|
- params.push(query.endDate);
|
|
|
- }
|
|
|
- if (query.type) {
|
|
|
- sql += ' AND type = ?';
|
|
|
- params.push(query.type);
|
|
|
- }
|
|
|
- if (query.groupId) {
|
|
|
- sql += ' AND group_id = ?';
|
|
|
- params.push(query.groupId);
|
|
|
- }
|
|
|
+ if (query.startDate) {
|
|
|
+ sql += ' AND t.time >= ?';
|
|
|
+ params.push(query.startDate);
|
|
|
+ }
|
|
|
+ if (query.endDate) {
|
|
|
+ sql += ' AND t.time <= ?';
|
|
|
+ params.push(query.endDate);
|
|
|
+ }
|
|
|
+ if (query.type) {
|
|
|
+ sql += ' AND t.type = ?';
|
|
|
+ params.push(query.type);
|
|
|
+ }
|
|
|
+ if (query.groupId) {
|
|
|
+ sql += ' AND t.group_id = ?';
|
|
|
+ params.push(query.groupId);
|
|
|
+ }
|
|
|
|
|
|
- // 获取总数
|
|
|
- const [countResult] = await pool.query(
|
|
|
- sql.replace('SELECT *', 'SELECT COUNT(*) as total'),
|
|
|
- params
|
|
|
- );
|
|
|
- const total = countResult[0].total;
|
|
|
+ console.log('SQL查询:', sql);
|
|
|
+ console.log('参数:', params);
|
|
|
|
|
|
- // 获取分页数据
|
|
|
- sql += ' ORDER BY time DESC LIMIT ? OFFSET ?';
|
|
|
- params.push(limit, (page - 1) * limit);
|
|
|
+ // 获取总数
|
|
|
+ const countSql = `
|
|
|
+ SELECT COUNT(*) as total
|
|
|
+ FROM transactions t
|
|
|
+ WHERE 1=1
|
|
|
+ ${query.startDate ? 'AND t.time >= ?' : ''}
|
|
|
+ ${query.endDate ? 'AND t.time <= ?' : ''}
|
|
|
+ ${query.type ? 'AND t.type = ?' : ''}
|
|
|
+ ${query.groupId ? 'AND t.group_id = ?' : ''}
|
|
|
+ `;
|
|
|
+
|
|
|
+ const [countResult] = await pool.query(countSql, params);
|
|
|
+ const total = countResult[0]?.total || 0;
|
|
|
|
|
|
- const [rows] = await pool.query(sql, params);
|
|
|
+ // 获取分页数据
|
|
|
+ sql += ' ORDER BY t.time DESC LIMIT ? OFFSET ?';
|
|
|
+ params.push(limit, (page - 1) * limit);
|
|
|
|
|
|
- return {
|
|
|
- transactions: rows,
|
|
|
- total,
|
|
|
- page: parseInt(page),
|
|
|
- pages: Math.ceil(total / limit)
|
|
|
- };
|
|
|
+ const [rows] = await pool.query(sql, params);
|
|
|
+ console.log('查询结果数量:', rows.length);
|
|
|
+
|
|
|
+ return {
|
|
|
+ transactions: rows,
|
|
|
+ total,
|
|
|
+ page: parseInt(page),
|
|
|
+ pages: Math.ceil(total / limit)
|
|
|
+ };
|
|
|
+ } catch (error) {
|
|
|
+ console.error('查询交易列表失败:', error);
|
|
|
+ throw error;
|
|
|
+ }
|
|
|
},
|
|
|
|
|
|
// 创建交易
|
|
|
create: async (transactionData) => {
|
|
|
const [result] = await pool.query(
|
|
|
- 'INSERT INTO transactions (group_id, group_name, type, amount) VALUES (?, ?, ?, ?)',
|
|
|
- [transactionData.groupId, transactionData.groupName, transactionData.type, transactionData.amount]
|
|
|
+ 'INSERT INTO transactions (group_id, group_name, type, amount, remark, operator_id) VALUES (?, ?, ?, ?, ?, ?)',
|
|
|
+ [
|
|
|
+ transactionData.groupId,
|
|
|
+ transactionData.groupName,
|
|
|
+ transactionData.type,
|
|
|
+ transactionData.amount,
|
|
|
+ transactionData.remark || null,
|
|
|
+ transactionData.operatorId
|
|
|
+ ]
|
|
|
);
|
|
|
return result.insertId;
|
|
|
},
|
|
@@ -97,7 +175,15 @@ const Transaction = {
|
|
|
pool.query('SELECT COUNT(*) as count FROM transactions').then(([rows]) => rows[0].count),
|
|
|
pool.query('SELECT SUM(amount) as total FROM transactions').then(([rows]) => rows[0].total || 0),
|
|
|
pool.query('SELECT COUNT(*) as count FROM transactions WHERE time >= ?', [today]).then(([rows]) => rows[0].count),
|
|
|
- pool.query('SELECT * FROM transactions ORDER BY time DESC LIMIT 5').then(([rows]) => rows)
|
|
|
+ pool.query(`
|
|
|
+ SELECT
|
|
|
+ t.*,
|
|
|
+ u.username as operator_name
|
|
|
+ FROM transactions t
|
|
|
+ LEFT JOIN users u ON t.operator_id = u.id
|
|
|
+ ORDER BY t.time DESC
|
|
|
+ LIMIT 5
|
|
|
+ `).then(([rows]) => rows)
|
|
|
]);
|
|
|
|
|
|
// 获取活跃群组
|
|
@@ -200,8 +286,10 @@ const Transaction = {
|
|
|
let sql = `
|
|
|
SELECT
|
|
|
t.*,
|
|
|
+ u.username as operator_name,
|
|
|
DATE_FORMAT(t.time, '%Y-%m-%d %H:%i:%s') as formatted_time
|
|
|
- FROM transactions t
|
|
|
+ FROM transactions t
|
|
|
+ LEFT JOIN users u ON t.operator_id = u.id
|
|
|
WHERE t.group_id = ?
|
|
|
`;
|
|
|
const params = [groupId];
|
|
@@ -220,10 +308,17 @@ const Transaction = {
|
|
|
}
|
|
|
|
|
|
// 获取总数
|
|
|
- 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 countSql = `
|
|
|
+ SELECT COUNT(*) as total
|
|
|
+ FROM transactions t
|
|
|
+ WHERE 1=1
|
|
|
+ ${startDate ? 'AND t.time >= ?' : ''}
|
|
|
+ ${endDate ? 'AND t.time <= ?' : ''}
|
|
|
+ ${type ? 'AND t.type = ?' : ''}
|
|
|
+ ${groupId ? 'AND t.group_id = ?' : ''}
|
|
|
+ `;
|
|
|
+
|
|
|
+ const [countResult] = await pool.query(countSql, params);
|
|
|
const total = countResult[0].total;
|
|
|
|
|
|
// 获取分页数据
|
|
@@ -259,10 +354,14 @@ const Transaction = {
|
|
|
// 根据ID查找交易记录
|
|
|
findById: async (id) => {
|
|
|
try {
|
|
|
- const [rows] = await pool.query(
|
|
|
- 'SELECT * FROM transactions WHERE id = ?',
|
|
|
- [id]
|
|
|
- );
|
|
|
+ const [rows] = await pool.query(`
|
|
|
+ SELECT
|
|
|
+ t.*,
|
|
|
+ u.username as operator_name
|
|
|
+ FROM transactions t
|
|
|
+ LEFT JOIN users u ON t.operator_id = u.id
|
|
|
+ WHERE t.id = ?
|
|
|
+ `, [id]);
|
|
|
return rows[0] || null;
|
|
|
} catch (error) {
|
|
|
console.error('查询交易记录失败:', error);
|