Transaction.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. const { pool } = require('../config/database');
  2. // 创建交易表
  3. const createTransactionTable = async () => {
  4. try {
  5. await pool.query(`
  6. CREATE TABLE IF NOT EXISTS transactions (
  7. id INT AUTO_INCREMENT PRIMARY KEY,
  8. group_id VARCHAR(50) NOT NULL,
  9. group_name VARCHAR(100) NOT NULL,
  10. type ENUM('deposit', 'withdrawal') NOT NULL,
  11. amount DECIMAL(10,2) NOT NULL,
  12. time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  13. INDEX idx_group_time (group_id, time)
  14. )
  15. `);
  16. } catch (error) {
  17. console.error('创建交易表失败:', error);
  18. }
  19. };
  20. // 初始化表
  21. createTransactionTable();
  22. // 交易相关方法
  23. const Transaction = {
  24. // 获取交易列表
  25. findAll: async (query = {}, page = 1, limit = 10) => {
  26. let sql = 'SELECT * FROM transactions WHERE 1=1';
  27. const params = [];
  28. if (query.startDate) {
  29. sql += ' AND time >= ?';
  30. params.push(query.startDate);
  31. }
  32. if (query.endDate) {
  33. sql += ' AND time <= ?';
  34. params.push(query.endDate);
  35. }
  36. if (query.type) {
  37. sql += ' AND type = ?';
  38. params.push(query.type);
  39. }
  40. if (query.groupId) {
  41. sql += ' AND group_id = ?';
  42. params.push(query.groupId);
  43. }
  44. // 获取总数
  45. const [countResult] = await pool.query(
  46. sql.replace('SELECT *', 'SELECT COUNT(*) as total'),
  47. params
  48. );
  49. const total = countResult[0].total;
  50. // 获取分页数据
  51. sql += ' ORDER BY time DESC LIMIT ? OFFSET ?';
  52. params.push(limit, (page - 1) * limit);
  53. const [rows] = await pool.query(sql, params);
  54. return {
  55. transactions: rows,
  56. total,
  57. page: parseInt(page),
  58. pages: Math.ceil(total / limit)
  59. };
  60. },
  61. // 创建交易
  62. create: async (transactionData) => {
  63. const [result] = await pool.query(
  64. 'INSERT INTO transactions (group_id, group_name, type, amount) VALUES (?, ?, ?, ?)',
  65. [transactionData.groupId, transactionData.groupName, transactionData.type, transactionData.amount]
  66. );
  67. return result.insertId;
  68. },
  69. // 删除交易
  70. delete: async (id) => {
  71. await pool.query('DELETE FROM transactions WHERE id = ?', [id]);
  72. },
  73. // 获取仪表板数据
  74. getDashboardData: async () => {
  75. const today = new Date();
  76. today.setHours(0, 0, 0, 0);
  77. const [
  78. totalGroups,
  79. totalTransactions,
  80. totalAmount,
  81. todayTransactions,
  82. recentTransactions
  83. ] = await Promise.all([
  84. pool.query('SELECT COUNT(*) as count FROM groups').then(([rows]) => rows[0].count),
  85. pool.query('SELECT COUNT(*) as count FROM transactions').then(([rows]) => rows[0].count),
  86. pool.query('SELECT SUM(amount) as total FROM transactions').then(([rows]) => rows[0].total || 0),
  87. pool.query('SELECT COUNT(*) as count FROM transactions WHERE time >= ?', [today]).then(([rows]) => rows[0].count),
  88. pool.query('SELECT * FROM transactions ORDER BY time DESC LIMIT 5').then(([rows]) => rows)
  89. ]);
  90. // 获取活跃群组
  91. const [activeGroups] = await pool.query(`
  92. SELECT
  93. g.group_name as name,
  94. COUNT(t.id) as totalTransactions,
  95. SUM(CASE WHEN t.time >= ? THEN 1 ELSE 0 END) as todayTransactions
  96. FROM groups g
  97. LEFT JOIN transactions t ON g.group_id = t.group_id
  98. GROUP BY g.id
  99. ORDER BY todayTransactions DESC
  100. LIMIT 5
  101. `, [today]);
  102. return {
  103. totalGroups,
  104. totalTransactions,
  105. totalAmount,
  106. todayTransactions,
  107. recentTransactions,
  108. activeGroups
  109. };
  110. },
  111. // 入款方法
  112. deposit: async (transactionData) => {
  113. try {
  114. const id = await Transaction.create({
  115. groupId: transactionData.groupId,
  116. groupName: transactionData.groupName,
  117. type: 'deposit',
  118. amount: parseFloat(transactionData.amount)
  119. });
  120. const transaction = await Transaction.findById(id);
  121. if (transaction) {
  122. return {
  123. success: true,
  124. transaction,
  125. message: '入款记录创建成功'
  126. };
  127. } else {
  128. return {
  129. success: false,
  130. message: '入款记录创建失败'
  131. };
  132. }
  133. } catch (error) {
  134. console.error('入款记录创建失败:', error);
  135. return {
  136. success: false,
  137. message: '入款记录创建失败,请稍后重试'
  138. };
  139. }
  140. },
  141. // 出款方法
  142. withdrawal: async (transactionData) => {
  143. try {
  144. const id = await Transaction.create({
  145. groupId: transactionData.groupId,
  146. groupName: transactionData.groupName,
  147. type: 'withdrawal',
  148. amount: parseFloat(transactionData.amount)
  149. });
  150. const transaction = await Transaction.findById(id);
  151. if (transaction) {
  152. return {
  153. success: true,
  154. transaction,
  155. message: '出款记录创建成功'
  156. };
  157. } else {
  158. return {
  159. success: false,
  160. message: '出款记录创建失败'
  161. };
  162. }
  163. } catch (error) {
  164. console.error('出款记录创建失败:', error);
  165. return {
  166. success: false,
  167. message: '出款记录创建失败,请稍后重试'
  168. };
  169. }
  170. },
  171. // 查询群组账单
  172. getGroupTransactions: async (groupId, options = {}) => {
  173. const {
  174. startDate,
  175. endDate,
  176. type,
  177. page = 1,
  178. limit = 10
  179. } = options;
  180. let sql = `
  181. SELECT
  182. t.*,
  183. DATE_FORMAT(t.time, '%Y-%m-%d %H:%i:%s') as formatted_time
  184. FROM transactions t
  185. WHERE t.group_id = ?
  186. `;
  187. const params = [groupId];
  188. if (startDate) {
  189. sql += ' AND t.time >= ?';
  190. params.push(startDate);
  191. }
  192. if (endDate) {
  193. sql += ' AND t.time <= ?';
  194. params.push(endDate);
  195. }
  196. if (type) {
  197. sql += ' AND t.type = ?';
  198. params.push(type);
  199. }
  200. // 获取总数
  201. const [countResult] = await pool.query(
  202. sql.replace('SELECT t.*, DATE_FORMAT(t.time, \'%Y-%m-%d %H:%i:%s\') as formatted_time', 'SELECT COUNT(*) as total'),
  203. params
  204. );
  205. const total = countResult[0].total;
  206. // 获取分页数据
  207. sql += ' ORDER BY t.time DESC LIMIT ? OFFSET ?';
  208. params.push(limit, (page - 1) * limit);
  209. const [rows] = await pool.query(sql, params);
  210. // 计算总入款和总出款
  211. const [summary] = await pool.query(`
  212. SELECT
  213. SUM(CASE WHEN type = 'deposit' THEN amount ELSE 0 END) as total_deposit,
  214. SUM(CASE WHEN type = 'withdrawal' THEN amount ELSE 0 END) as total_withdrawal
  215. FROM transactions
  216. WHERE group_id = ?
  217. ${startDate ? 'AND time >= ?' : ''}
  218. ${endDate ? 'AND time <= ?' : ''}
  219. `, [groupId, ...(startDate ? [startDate] : []), ...(endDate ? [endDate] : [])]);
  220. return {
  221. transactions: rows,
  222. total,
  223. page: parseInt(page),
  224. pages: Math.ceil(total / limit),
  225. summary: {
  226. totalDeposit: summary[0].total_deposit || 0,
  227. totalWithdrawal: summary[0].total_withdrawal || 0,
  228. balance: (summary[0].total_deposit || 0) - (summary[0].total_withdrawal || 0)
  229. }
  230. };
  231. },
  232. // 根据ID查找交易记录
  233. findById: async (id) => {
  234. try {
  235. const [rows] = await pool.query(
  236. 'SELECT * FROM transactions WHERE id = ?',
  237. [id]
  238. );
  239. return rows[0] || null;
  240. } catch (error) {
  241. console.error('查询交易记录失败:', error);
  242. return null;
  243. }
  244. }
  245. };
  246. module.exports = Transaction;