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;
|