// 数据库连接配置 // 使用腾讯云数据库 import mysql from 'mysql2/promise' // 数据库配置(不含database,用于创建数据库) const dbConfigWithoutDB = { host: '56b4c23f6853c.gz.cdb.myqcloud.com', port: 14413, user: 'cdb_outerroot', password: 'Zhiqun1984', waitForConnections: true, connectionLimit: 10, queueLimit: 0, } // 数据库配置(含database) const dbConfig = { ...dbConfigWithoutDB, database: 'soul_experiment', } // 创建连接池 let pool: mysql.Pool | null = null export function getPool() { if (!pool) { pool = mysql.createPool(dbConfig) } return pool } // 创建数据库(如果不存在) export async function createDatabaseIfNotExists() { const conn = await mysql.createConnection(dbConfigWithoutDB) try { await conn.execute('CREATE DATABASE IF NOT EXISTS soul_experiment CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci') console.log('Database soul_experiment created or already exists') return true } catch (error) { console.error('Error creating database:', error) throw error } finally { await conn.end() } } // 执行查询 export async function query(sql: string, params?: any[]): Promise { const pool = getPool() const [rows] = await pool.execute(sql, params) return rows as T[] } // 执行单条插入/更新/删除 export async function execute(sql: string, params?: any[]): Promise { const pool = getPool() const [result] = await pool.execute(sql, params) return result as mysql.ResultSetHeader } // 用户相关操作 export const userDB = { // 获取所有用户 async getAll() { return query(`SELECT * FROM users ORDER BY created_at DESC`) }, // 根据ID获取用户 async getById(id: string) { const rows = await query(`SELECT * FROM users WHERE id = ?`, [id]) return rows[0] || null }, // 根据手机号获取用户 async getByPhone(phone: string) { const rows = await query(`SELECT * FROM users WHERE phone = ?`, [phone]) return rows[0] || null }, // 创建用户 async create(user: { id: string phone: string nickname: string password?: string is_admin?: boolean referral_code: string referred_by?: string }) { await execute( `INSERT INTO users (id, phone, nickname, password, is_admin, referral_code, referred_by, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, NOW())`, [user.id, user.phone, user.nickname, user.password || '', user.is_admin || false, user.referral_code, user.referred_by || null] ) return user }, // 更新用户 async update(id: string, updates: Partial<{ nickname: string password: string is_admin: boolean has_full_book: boolean earnings: number pending_earnings: number withdrawn_earnings: number referral_count: number match_count_today: number last_match_date: string }>) { const fields: string[] = [] const values: any[] = [] Object.entries(updates).forEach(([key, value]) => { if (value !== undefined) { fields.push(`${key} = ?`) values.push(value) } }) if (fields.length === 0) return values.push(id) await execute(`UPDATE users SET ${fields.join(', ')} WHERE id = ?`, values) }, // 删除用户 async delete(id: string) { await execute(`DELETE FROM users WHERE id = ?`, [id]) }, // 验证密码 async verifyPassword(phone: string, password: string) { const rows = await query(`SELECT * FROM users WHERE phone = ? AND password = ?`, [phone, password]) return rows[0] || null }, // 更新匹配次数 async updateMatchCount(userId: string) { const today = new Date().toISOString().split('T')[0] const user = await this.getById(userId) if (user?.last_match_date === today) { await execute( `UPDATE users SET match_count_today = match_count_today + 1 WHERE id = ?`, [userId] ) } else { await execute( `UPDATE users SET match_count_today = 1, last_match_date = ? WHERE id = ?`, [today, userId] ) } }, // 获取今日匹配次数 async getMatchCount(userId: string) { const today = new Date().toISOString().split('T')[0] const rows = await query( `SELECT match_count_today FROM users WHERE id = ? AND last_match_date = ?`, [userId, today] ) return rows[0]?.match_count_today || 0 } } // 购买记录相关操作 export const purchaseDB = { async getAll() { return query(`SELECT * FROM purchases ORDER BY created_at DESC`) }, async getByUserId(userId: string) { return query(`SELECT * FROM purchases WHERE user_id = ? ORDER BY created_at DESC`, [userId]) }, async create(purchase: { id: string user_id: string type: 'section' | 'fullbook' | 'match' section_id?: string section_title?: string amount: number payment_method?: string referral_code?: string referrer_earnings?: number status: string }) { await execute( `INSERT INTO purchases (id, user_id, type, section_id, section_title, amount, payment_method, referral_code, referrer_earnings, status, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())`, [purchase.id, purchase.user_id, purchase.type, purchase.section_id || null, purchase.section_title || null, purchase.amount, purchase.payment_method || null, purchase.referral_code || null, purchase.referrer_earnings || 0, purchase.status] ) return purchase } } // 分销绑定相关操作 export const distributionDB = { async getAllBindings() { return query(`SELECT * FROM referral_bindings ORDER BY bound_at DESC`) }, async getBindingsByReferrer(referrerId: string) { return query(`SELECT * FROM referral_bindings WHERE referrer_id = ? ORDER BY bound_at DESC`, [referrerId]) }, async createBinding(binding: { id: string referrer_id: string referee_id: string referrer_code: string bound_at: string expires_at: string status: string }) { await execute( `INSERT INTO referral_bindings (id, referrer_id, referee_id, referrer_code, bound_at, expires_at, status) VALUES (?, ?, ?, ?, ?, ?, ?)`, [binding.id, binding.referrer_id, binding.referee_id, binding.referrer_code, binding.bound_at, binding.expires_at, binding.status] ) return binding }, async updateBindingStatus(id: string, status: string) { await execute(`UPDATE referral_bindings SET status = ? WHERE id = ?`, [status, id]) }, async getActiveBindingByReferee(refereeId: string) { const rows = await query( `SELECT * FROM referral_bindings WHERE referee_id = ? AND status = 'active' AND expires_at > NOW()`, [refereeId] ) return rows[0] || null }, // 佣金记录 async getAllCommissions() { return query(`SELECT * FROM distribution_commissions ORDER BY created_at DESC`) }, async createCommission(commission: { id: string binding_id: string referrer_id: string referee_id: string order_id: string amount: number commission_rate: number commission_amount: number status: string }) { await execute( `INSERT INTO distribution_commissions (id, binding_id, referrer_id, referee_id, order_id, amount, commission_rate, commission_amount, status, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())`, [commission.id, commission.binding_id, commission.referrer_id, commission.referee_id, commission.order_id, commission.amount, commission.commission_rate, commission.commission_amount, commission.status] ) return commission } } // 提现记录相关操作 export const withdrawalDB = { async getAll() { return query(`SELECT * FROM withdrawals ORDER BY created_at DESC`) }, async getByUserId(userId: string) { return query(`SELECT * FROM withdrawals WHERE user_id = ? ORDER BY created_at DESC`, [userId]) }, async create(withdrawal: { id: string user_id: string amount: number method: string account: string name: string status: string }) { await execute( `INSERT INTO withdrawals (id, user_id, amount, method, account, name, status, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, NOW())`, [withdrawal.id, withdrawal.user_id, withdrawal.amount, withdrawal.method, withdrawal.account, withdrawal.name, withdrawal.status] ) return withdrawal }, async updateStatus(id: string, status: string) { const completedAt = status === 'completed' ? ', completed_at = NOW()' : '' await execute(`UPDATE withdrawals SET status = ?${completedAt} WHERE id = ?`, [status, id]) } } // 系统设置相关操作 export const settingsDB = { async get() { const rows = await query(`SELECT * FROM settings WHERE id = 1`) return rows[0] || null }, async update(settings: Record) { const json = JSON.stringify(settings) await execute( `INSERT INTO settings (id, data, updated_at) VALUES (1, ?, NOW()) ON DUPLICATE KEY UPDATE data = ?, updated_at = NOW()`, [json, json] ) } } // book内容相关操作 export const bookDB = { async getAllSections() { return query(`SELECT * FROM book_sections ORDER BY sort_order ASC`) }, async getSection(id: string) { const rows = await query(`SELECT * FROM book_sections WHERE id = ?`, [id]) return rows[0] || null }, async updateSection(id: string, updates: { title?: string; content?: string; price?: number; is_free?: boolean }) { const fields: string[] = [] const values: any[] = [] Object.entries(updates).forEach(([key, value]) => { if (value !== undefined) { fields.push(`${key} = ?`) values.push(value) } }) if (fields.length === 0) return fields.push('updated_at = NOW()') values.push(id) await execute(`UPDATE book_sections SET ${fields.join(', ')} WHERE id = ?`, values) }, async createSection(section: { id: string part_id: string chapter_id: string title: string content: string price: number is_free: boolean sort_order: number }) { await execute( `INSERT INTO book_sections (id, part_id, chapter_id, title, content, price, is_free, sort_order, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())`, [section.id, section.part_id, section.chapter_id, section.title, section.content, section.price, section.is_free, section.sort_order] ) return section }, // 导出所有章节 async exportAll() { const sections = await this.getAllSections() return JSON.stringify(sections, null, 2) }, // 导入章节 async importSections(sectionsJson: string) { const sections = JSON.parse(sectionsJson) for (const section of sections) { const existing = await this.getSection(section.id) if (existing) { await this.updateSection(section.id, section) } else { await this.createSection(section) } } return sections.length } } // 初始化数据库表 export async function initDatabase() { // 先创建数据库 await createDatabaseIfNotExists() const pool = getPool() // 用户表 await pool.execute(` CREATE TABLE IF NOT EXISTS users ( id VARCHAR(50) PRIMARY KEY, phone VARCHAR(20) UNIQUE NOT NULL, nickname VARCHAR(100) NOT NULL, password VARCHAR(100) DEFAULT '', is_admin BOOLEAN DEFAULT FALSE, has_full_book BOOLEAN DEFAULT FALSE, referral_code VARCHAR(20) UNIQUE, referred_by VARCHAR(20), earnings DECIMAL(10,2) DEFAULT 0, pending_earnings DECIMAL(10,2) DEFAULT 0, withdrawn_earnings DECIMAL(10,2) DEFAULT 0, referral_count INT DEFAULT 0, match_count_today INT DEFAULT 0, last_match_date DATE, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_phone (phone), INDEX idx_referral_code (referral_code) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 `) // 购买记录表 await pool.execute(` CREATE TABLE IF NOT EXISTS purchases ( id VARCHAR(50) PRIMARY KEY, user_id VARCHAR(50) NOT NULL, type ENUM('section', 'fullbook', 'match') NOT NULL, section_id VARCHAR(20), section_title VARCHAR(200), amount DECIMAL(10,2) NOT NULL, payment_method VARCHAR(20), referral_code VARCHAR(20), referrer_earnings DECIMAL(10,2) DEFAULT 0, status ENUM('pending', 'completed', 'refunded') DEFAULT 'pending', created_at DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_user_id (user_id), INDEX idx_status (status) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 `) // 分销绑定表 await pool.execute(` CREATE TABLE IF NOT EXISTS referral_bindings ( id VARCHAR(50) PRIMARY KEY, referrer_id VARCHAR(50) NOT NULL, referee_id VARCHAR(50) NOT NULL, referrer_code VARCHAR(20) NOT NULL, bound_at DATETIME NOT NULL, expires_at DATETIME NOT NULL, status ENUM('active', 'converted', 'expired') DEFAULT 'active', INDEX idx_referrer (referrer_id), INDEX idx_referee (referee_id), INDEX idx_status (status) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 `) // 分销佣金表 await pool.execute(` CREATE TABLE IF NOT EXISTS distribution_commissions ( id VARCHAR(50) PRIMARY KEY, binding_id VARCHAR(50) NOT NULL, referrer_id VARCHAR(50) NOT NULL, referee_id VARCHAR(50) NOT NULL, order_id VARCHAR(50) NOT NULL, amount DECIMAL(10,2) NOT NULL, commission_rate DECIMAL(5,2) NOT NULL, commission_amount DECIMAL(10,2) NOT NULL, status ENUM('pending', 'paid', 'cancelled') DEFAULT 'pending', created_at DATETIME DEFAULT CURRENT_TIMESTAMP, paid_at DATETIME, INDEX idx_referrer (referrer_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 `) // 提现记录表 await pool.execute(` CREATE TABLE IF NOT EXISTS withdrawals ( id VARCHAR(50) PRIMARY KEY, user_id VARCHAR(50) NOT NULL, amount DECIMAL(10,2) NOT NULL, method ENUM('wechat', 'alipay') NOT NULL, account VARCHAR(100) NOT NULL, name VARCHAR(50) NOT NULL, status ENUM('pending', 'completed', 'rejected') DEFAULT 'pending', created_at DATETIME DEFAULT CURRENT_TIMESTAMP, completed_at DATETIME, INDEX idx_user_id (user_id), INDEX idx_status (status) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 `) // 系统设置表 await pool.execute(` CREATE TABLE IF NOT EXISTS settings ( id INT PRIMARY KEY, data JSON, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 `) // book章节表 await pool.execute(` CREATE TABLE IF NOT EXISTS book_sections ( id VARCHAR(20) PRIMARY KEY, part_id VARCHAR(20) NOT NULL, chapter_id VARCHAR(20) NOT NULL, title VARCHAR(200) NOT NULL, content LONGTEXT, price DECIMAL(10,2) DEFAULT 1, is_free BOOLEAN DEFAULT FALSE, sort_order INT DEFAULT 0, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_part (part_id), INDEX idx_chapter (chapter_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 `) console.log('Database tables initialized successfully') }