202 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			202 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | const express = require('express'); | |||
|  | const router = express.Router(); | |||
|  | const WechatPayService = require('../services/wechatPayService'); | |||
|  | const { getDB } = require('../database'); | |||
|  | const { auth, paymentAuth } = require('../middleware/auth'); | |||
|  | 
 | |||
|  | // 创建微信支付服务实例
 | |||
|  | const wechatPayService = new WechatPayService(); | |||
|  | 
 | |||
|  | /** | |||
|  |  * 创建注册支付订单 (API v3 - H5支付) | |||
|  |  * POST /api/wechat-pay/create-registration-order | |||
|  |  */ | |||
|  | router.post('/create-registration-order', paymentAuth, async (req, res) => { | |||
|  |   try { | |||
|  |     const userId = req.user.id; | |||
|  |     const username = req.user.username; | |||
|  |     const phone = req.user.phone; | |||
|  |      | |||
|  |     // 获取客户端IP
 | |||
|  |     const clientIp = req.headers['x-forwarded-for'] ||  | |||
|  |                     req.headers['x-real-ip'] ||  | |||
|  |                     req.connection.remoteAddress ||  | |||
|  |                     req.socket.remoteAddress || | |||
|  |                     (req.connection.socket ? req.connection.socket.remoteAddress : null) || | |||
|  |                     '127.0.0.1'; | |||
|  | 
 | |||
|  |     // 检查用户是否已经支付过
 | |||
|  |     const db = getDB(); | |||
|  |     const [existingOrders] = await db.execute( | |||
|  |       'SELECT id FROM payment_orders WHERE user_id = ? AND status = "paid"', | |||
|  |       [userId] | |||
|  |     ); | |||
|  | 
 | |||
|  |     if (existingOrders.length > 0) { | |||
|  |       return res.status(400).json({ | |||
|  |         success: false, | |||
|  |         message: '用户已完成支付,无需重复支付' | |||
|  |       }); | |||
|  |     } | |||
|  | 
 | |||
|  |     console.log('创建H5支付订单:', { | |||
|  |       userId, | |||
|  |       username, | |||
|  |       phone, | |||
|  |       clientIp | |||
|  |     }); | |||
|  | 
 | |||
|  |     // 创建H5支付订单
 | |||
|  |     const result = await wechatPayService.createRegistrationPayOrder({ | |||
|  |       userId, | |||
|  |       username, | |||
|  |       phone, | |||
|  |       clientIp | |||
|  |     }); | |||
|  | 
 | |||
|  |     if (result.success) { | |||
|  |       res.json({ | |||
|  |         success: true, | |||
|  |         data: { | |||
|  |           outTradeNo: result.data.outTradeNo, | |||
|  |           h5Url: result.data.h5Url, | |||
|  |           paymentType: result.data.paymentType | |||
|  |         } | |||
|  |       }); | |||
|  |     } else { | |||
|  |       res.status(500).json({ | |||
|  |         success: false, | |||
|  |         message: '创建支付订单失败' | |||
|  |       }); | |||
|  |     } | |||
|  |   } catch (error) { | |||
|  |     console.error('创建H5支付订单异常:', error); | |||
|  |     res.status(500).json({ | |||
|  |       success: false, | |||
|  |       message: error.message || '服务器内部错误' | |||
|  |     }); | |||
|  |   } | |||
|  | }); | |||
|  | 
 | |||
|  | // H5支付不需要获取openid,移除相关接口
 | |||
|  | 
 | |||
|  | /** | |||
|  |  * 微信支付回调接口 (API v3) | |||
|  |  * POST /api/wechat-pay/notify | |||
|  |  */ | |||
|  | router.post('/notify', async (req, res) => { | |||
|  |   try { | |||
|  |     // API v3 回调是JSON格式
 | |||
|  |     const notifyData = req.body; | |||
|  |      | |||
|  |     // 获取请求头中的签名信息
 | |||
|  |     const signature = req.headers['wechatpay-signature']; | |||
|  |     const timestamp = req.headers['wechatpay-timestamp']; | |||
|  |     const nonce = req.headers['wechatpay-nonce']; | |||
|  |     const serial = req.headers['wechatpay-serial']; | |||
|  |      | |||
|  |     console.log('收到API v3支付回调:', { | |||
|  |       signature, | |||
|  |       timestamp, | |||
|  |       nonce, | |||
|  |       serial, | |||
|  |       body: notifyData | |||
|  |     }); | |||
|  |      | |||
|  |     // 验证签名和处理回调
 | |||
|  |     const result = await wechatPayService.handleV3PaymentNotify({ | |||
|  |       signature, | |||
|  |       timestamp, | |||
|  |       nonce, | |||
|  |       serial, | |||
|  |       body: JSON.stringify(notifyData) | |||
|  |     }); | |||
|  |      | |||
|  |     if (result.success) { | |||
|  |       // API v3 成功响应
 | |||
|  |       res.status(200).json({ code: 'SUCCESS', message: '成功' }); | |||
|  |     } else { | |||
|  |       // API v3 失败响应
 | |||
|  |       res.status(400).json({ code: 'FAIL', message: result.message || '处理失败' }); | |||
|  |     } | |||
|  |   } catch (error) { | |||
|  |     console.error('支付回调处理异常:', error); | |||
|  |     res.status(500).json({ code: 'ERROR', message: '服务器内部错误' }); | |||
|  |   } | |||
|  | }); | |||
|  | 
 | |||
|  | /** | |||
|  |  * 查询支付状态 | |||
|  |  * GET /api/wechat-pay/query-status/:outTradeNo | |||
|  |  */ | |||
|  | router.get('/query-status/:outTradeNo', paymentAuth, async (req, res) => { | |||
|  |   try { | |||
|  |     const { outTradeNo } = req.params; | |||
|  |     const userId = req.user.id; | |||
|  | 
 | |||
|  |     // 验证订单是否属于当前用户
 | |||
|  |     const db = getDB(); | |||
|  |     const [orders] = await db.execute( | |||
|  |       'SELECT id FROM payment_orders WHERE out_trade_no = ? AND user_id = ?', | |||
|  |       [outTradeNo, userId] | |||
|  |     ); | |||
|  | 
 | |||
|  |     if (orders.length === 0) { | |||
|  |       return res.status(404).json({ | |||
|  |         success: false, | |||
|  |         message: '订单不存在或无权限访问' | |||
|  |       }); | |||
|  |     } | |||
|  | 
 | |||
|  |     const result = await wechatPayService.queryPaymentStatus(outTradeNo); | |||
|  |     res.json(result); | |||
|  |   } catch (error) { | |||
|  |     console.error('查询支付状态失败:', error); | |||
|  |     res.status(500).json({ | |||
|  |       success: false, | |||
|  |       message: error.message || '查询支付状态失败' | |||
|  |     }); | |||
|  |   } | |||
|  | }); | |||
|  | 
 | |||
|  | /** | |||
|  |  * 检查用户支付状态 | |||
|  |  * GET /api/wechat-pay/check-user-payment | |||
|  |  */ | |||
|  | router.get('/check-user-payment', auth, async (req, res) => { | |||
|  |   try { | |||
|  |     const userId = req.user.id; | |||
|  |     const db = getDB(); | |||
|  | 
 | |||
|  |     // 查询用户支付状态
 | |||
|  |     const [users] = await db.execute( | |||
|  |       'SELECT payment_status FROM users WHERE id = ?', | |||
|  |       [userId] | |||
|  |     ); | |||
|  | 
 | |||
|  |     if (users.length === 0) { | |||
|  |       return res.status(404).json({ | |||
|  |         success: false, | |||
|  |         message: '用户不存在' | |||
|  |       }); | |||
|  |     } | |||
|  | 
 | |||
|  |     const paymentStatus = users[0].payment_status; | |||
|  | 
 | |||
|  |     res.json({ | |||
|  |       success: true, | |||
|  |       data: { | |||
|  |         paymentStatus, | |||
|  |         isPaid: paymentStatus === 'paid' | |||
|  |       } | |||
|  |     }); | |||
|  |   } catch (error) { | |||
|  |     console.error('检查用户支付状态失败:', error); | |||
|  |     res.status(500).json({ | |||
|  |       success: false, | |||
|  |       message: '检查支付状态失败' | |||
|  |     }); | |||
|  |   } | |||
|  | }); | |||
|  | 
 | |||
|  | module.exports = router; |