import { Pool } from 'pg' import crypto from 'crypto' // 创建数据库连接池 const pool = new Pool({ connectionString: process.env.DATABASE_URL, max: 20, // 最大连接数 idleTimeoutMillis: 30000, connectionTimeoutMillis: 2000, }) // 测试连接 pool.on('connect', () => { console.log('✅ Database connected') }) pool.on('error', (err) => { console.error('❌ Unexpected database error:', err) }) export default pool // 用户接口 export interface User { id: number name: string email: string password: string email_verified: boolean created_at: Date updated_at: Date provider?: string wechat_unionid?: string | null wechat_openid?: string | null } // 订单接口 export interface Order { id: number order_no: string user_id: number product_type: string // 'standard' | 'deployment' | 'custom' product_name: string amount: number status: string // 'pending' | 'paid' | 'failed' | 'cancelled' payment_method?: string trade_no?: string callback_data?: string created_at: Date updated_at: Date paid_at?: Date } // 数据库查询函数 export const db = { // 根据邮箱查找用户 async findUserByEmail(email: string): Promise { const result = await pool.query( 'SELECT * FROM users WHERE email = $1', [email] ) return result.rows[0] || null }, // 根据ID查找用户 async findUserById(id: number): Promise { const result = await pool.query( 'SELECT * FROM users WHERE id = $1', [id] ) return result.rows[0] || null }, // 创建新用户 async createUser( name: string, email: string, password: string ): Promise { const result = await pool.query( 'INSERT INTO users (name, email, password, email_verified, created_at, updated_at) VALUES ($1, $2, $3, $4, NOW(), NOW()) RETURNING *', [name, email, password, false] ) return result.rows[0] }, // 更新用户 async updateUser(id: number, data: Partial): Promise { const fields = [] const values = [] let index = 1 if (data.name !== undefined) { fields.push(`name = $${index++}`) values.push(data.name) } if (data.email !== undefined) { fields.push(`email = $${index++}`) values.push(data.email) } if (data.password !== undefined) { fields.push(`password = $${index++}`) values.push(data.password) } if (data.email_verified !== undefined) { fields.push(`email_verified = $${index++}`) values.push(data.email_verified) } fields.push(`updated_at = NOW()`) values.push(id) const query = `UPDATE users SET ${fields.join(', ')} WHERE id = $${index} RETURNING *` const result = await pool.query(query, values) return result.rows[0] }, // 删除用户 async deleteUser(id: number): Promise { const result = await pool.query('DELETE FROM users WHERE id = $1', [id]) return (result.rowCount ?? 0) > 0 }, // 获取所有用户(用于管理) async getAllUsers(): Promise { const result = await pool.query( 'SELECT id, name, email, email_verified, created_at FROM users ORDER BY created_at DESC' ) return result.rows }, // ========== 微信用户相关 ========== async findUserByWechat(unionid?: string | null, openid?: string | null): Promise { if (unionid) { const byUnion = await pool.query('SELECT * FROM users WHERE wechat_unionid = $1', [unionid]) if (byUnion.rows[0]) return byUnion.rows[0] } if (openid) { const byOpen = await pool.query('SELECT * FROM users WHERE wechat_openid = $1', [openid]) if (byOpen.rows[0]) return byOpen.rows[0] } return null }, async upsertWechatUser(params: { name?: string | null email?: string | null unionid?: string | null openid?: string | null hashedPassword: string }): Promise { const { name, email, unionid, openid, hashedPassword } = params const existing = await this.findUserByWechat(unionid ?? undefined, openid ?? undefined) if (existing) { return existing } const result = await pool.query( `INSERT INTO users (name, email, password, email_verified, provider, wechat_unionid, wechat_openid, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7, NOW(), NOW()) RETURNING *`, [ name || '微信用户', email || `${openid || unionid || crypto.randomUUID()}@wechat.local`, hashedPassword, true, 'wechat', unionid || null, openid || null, ] ) return result.rows[0] }, // ========== 订单相关操作 ========== // 创建订单 async createOrder( orderNo: string, userId: number, productType: string, productName: string, amount: number ): Promise { const result = await pool.query( 'INSERT INTO orders (order_no, user_id, product_type, product_name, amount, status, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, NOW(), NOW()) RETURNING *', [orderNo, userId, productType, productName, amount, 'pending'] ) return result.rows[0] }, // 根据订单号查找订单 async findOrderByOrderNo(orderNo: string): Promise { const result = await pool.query( 'SELECT * FROM orders WHERE order_no = $1', [orderNo] ) return result.rows[0] || null }, // 根据ID查找订单 async findOrderById(id: number): Promise { const result = await pool.query( 'SELECT * FROM orders WHERE id = $1', [id] ) return result.rows[0] || null }, // 更新订单状态 async updateOrderStatus( orderNo: string, status: string, tradeNo?: string, paymentMethod?: string, callbackData?: string ): Promise { const updates = ['status = $2', 'updated_at = NOW()'] const values: any[] = [orderNo, status] let index = 3 if (tradeNo) { updates.push(`trade_no = $${index++}`) values.push(tradeNo) } if (paymentMethod) { updates.push(`payment_method = $${index++}`) values.push(paymentMethod) } if (callbackData) { updates.push(`callback_data = $${index++}`) values.push(callbackData) } if (status === 'paid') { updates.push('paid_at = NOW()') } const query = `UPDATE orders SET ${updates.join(', ')} WHERE order_no = $1 RETURNING *` const result = await pool.query(query, values) return result.rows[0] }, // 获取用户的订单列表 async getUserOrders(userId: number): Promise { const result = await pool.query( 'SELECT * FROM orders WHERE user_id = $1 ORDER BY created_at DESC', [userId] ) return result.rows }, }