404 lines
10 KiB
JavaScript
404 lines
10 KiB
JavaScript
const express = require('express');
|
||
const router = express.Router();
|
||
const WechatPayService = require('../services/wechatPayService');
|
||
const AlipayService = require('../services/alipayservice');
|
||
const { getDB } = require('../database');
|
||
const { auth, paymentAuth } = require('../middleware/auth');
|
||
|
||
// 创建支付服务实例
|
||
const wechatPayService = new WechatPayService();
|
||
const alipayService = new AlipayService();
|
||
|
||
/**
|
||
* 获取支持的支付方式
|
||
* GET /api/payment/methods
|
||
*/
|
||
router.get('/methods', (req, res) => {
|
||
res.json({
|
||
success: true,
|
||
data: {
|
||
methods: [
|
||
{
|
||
code: 'wechat_h5',
|
||
name: '微信支付',
|
||
description: '微信H5支付',
|
||
icon: 'wechat',
|
||
enabled: true
|
||
},
|
||
{
|
||
code: 'alipay_wap',
|
||
name: '支付宝支付',
|
||
description: '支付宝手机网站支付',
|
||
icon: 'alipay',
|
||
enabled: true
|
||
}
|
||
]
|
||
}
|
||
});
|
||
});
|
||
|
||
/**
|
||
* 创建统一支付订单
|
||
* POST /api/payment/create-order
|
||
*/
|
||
router.post('/create-order', paymentAuth, async (req, res) => {
|
||
try {
|
||
const { paymentMethod } = req.body;
|
||
const userId = req.user.id;
|
||
const username = req.user.username;
|
||
const phone = req.user.phone;
|
||
|
||
// 验证支付方式
|
||
if (!paymentMethod || !['wechat_h5', 'alipay_wap'].includes(paymentMethod)) {
|
||
return res.status(400).json({
|
||
success: false,
|
||
message: '不支持的支付方式'
|
||
});
|
||
}
|
||
|
||
// 检查用户是否已经支付过
|
||
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: '用户已完成支付,无需重复支付'
|
||
});
|
||
}
|
||
|
||
let result;
|
||
|
||
// 获取客户端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';
|
||
|
||
// 根据支付方式创建订单
|
||
if (paymentMethod === 'wechat_h5') {
|
||
// 创建微信支付订单
|
||
result = await wechatPayService.createRegistrationPayOrder({
|
||
userId,
|
||
username,
|
||
phone,
|
||
clientIp
|
||
});
|
||
} else if (paymentMethod === 'alipay_wap') {
|
||
// 创建支付宝支付订单
|
||
result = await alipayService.createRegistrationPayOrder({
|
||
userId,
|
||
username,
|
||
phone,
|
||
clientIp
|
||
});
|
||
}
|
||
|
||
if (result && result.success) {
|
||
res.json({
|
||
success: true,
|
||
data: {
|
||
outTradeNo: result.data.outTradeNo,
|
||
payUrl: result.data.h5Url || result.data.payUrl,
|
||
paymentType: result.data.paymentType,
|
||
paymentMethod
|
||
}
|
||
});
|
||
} else {
|
||
res.status(500).json({
|
||
success: false,
|
||
message: '创建支付订单失败'
|
||
});
|
||
}
|
||
} catch (error) {
|
||
console.error('创建统一支付订单异常:', error);
|
||
res.status(500).json({
|
||
success: false,
|
||
message: error.message || '服务器内部错误'
|
||
});
|
||
}
|
||
});
|
||
|
||
/**
|
||
* 查询支付状态
|
||
* GET /api/payment/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: '订单不存在或无权限访问'
|
||
});
|
||
}
|
||
|
||
// 获取订单详细信息,包括trade_type
|
||
const [orderDetails] = await db.execute(
|
||
'SELECT id, trade_type FROM payment_orders WHERE id = ?',
|
||
[orders[0].id]
|
||
);
|
||
|
||
if (orderDetails.length === 0) {
|
||
return res.status(404).json({
|
||
success: false,
|
||
message: '订单详情不存在'
|
||
});
|
||
}
|
||
|
||
let result;
|
||
const tradeType = orderDetails[0].trade_type;
|
||
|
||
// 根据交易类型查询支付状态
|
||
if (tradeType === 'WECHAT_H5') {
|
||
// 查询微信支付状态
|
||
result = await wechatPayService.queryPaymentStatus(outTradeNo);
|
||
} else if (tradeType === 'ALIPAY_WAP') {
|
||
// 查询支付宝支付状态
|
||
result = await alipayService.queryPaymentStatus(outTradeNo);
|
||
} else {
|
||
return res.status(400).json({
|
||
success: false,
|
||
message: '不支持的支付方式'
|
||
});
|
||
}
|
||
|
||
res.json(result);
|
||
} catch (error) {
|
||
console.error('查询支付状态失败:', error);
|
||
res.status(500).json({
|
||
success: false,
|
||
message: error.message || '查询支付状态失败'
|
||
});
|
||
}
|
||
});
|
||
|
||
router.get('/pay-product/test', async (req, res) => {
|
||
console.log(123)
|
||
})
|
||
|
||
/**
|
||
* 获取用户支付记录
|
||
* GET /api/payment/orders
|
||
*/
|
||
router.get('/orders', paymentAuth, async (req, res) => {
|
||
try {
|
||
const userId = req.user.id;
|
||
const { page = 1, limit = 10, status } = req.query;
|
||
|
||
const offset = (page - 1) * limit;
|
||
const db = getDB();
|
||
|
||
let whereClause = 'WHERE user_id = ?';
|
||
let params = [userId];
|
||
|
||
if (status) {
|
||
whereClause += ' AND status = ?';
|
||
params.push(status);
|
||
}
|
||
|
||
// 查询订单列表
|
||
const [orders] = await db.execute(
|
||
`SELECT id, out_trade_no, transaction_id, total_fee, body, trade_type,
|
||
status, paid_at, created_at
|
||
FROM payment_orders
|
||
${whereClause}
|
||
ORDER BY created_at DESC
|
||
LIMIT ? OFFSET ?`,
|
||
[...params, parseInt(limit), parseInt(offset)]
|
||
);
|
||
|
||
// 查询总数
|
||
const [countResult] = await db.execute(
|
||
`SELECT COUNT(*) as total FROM payment_orders ${whereClause}`,
|
||
params
|
||
);
|
||
|
||
const total = countResult[0].total;
|
||
|
||
res.json({
|
||
success: true,
|
||
data: {
|
||
orders: orders.map(order => ({
|
||
...order,
|
||
total_fee: order.total_fee / 100, // 转换为元
|
||
payment_method_name: order.trade_type && order.trade_type.startsWith('ALIPAY') ? '支付宝支付' : '微信支付'
|
||
})),
|
||
pagination: {
|
||
page: parseInt(page),
|
||
limit: parseInt(limit),
|
||
total,
|
||
pages: Math.ceil(total / limit)
|
||
}
|
||
}
|
||
});
|
||
} catch (error) {
|
||
console.error('获取支付记录失败:', error);
|
||
res.status(500).json({
|
||
success: false,
|
||
message: '获取支付记录失败'
|
||
});
|
||
}
|
||
});
|
||
|
||
/**
|
||
* 检查用户支付状态
|
||
* GET /api/payment/check-status
|
||
*/
|
||
router.get('/check-status', 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;
|
||
|
||
// 查询最近的支付订单
|
||
const [recentOrders] = await db.execute(
|
||
`SELECT out_trade_no, trade_type, status, total_fee, paid_at
|
||
FROM payment_orders
|
||
WHERE user_id = ?
|
||
ORDER BY created_at DESC
|
||
LIMIT 1`,
|
||
[userId]
|
||
);
|
||
|
||
res.json({
|
||
success: true,
|
||
data: {
|
||
paymentStatus,
|
||
isPaid: paymentStatus === 'paid',
|
||
recentOrder: recentOrders.length > 0 ? {
|
||
...recentOrders[0],
|
||
total_fee: recentOrders[0].total_fee / 100,
|
||
payment_method_name: recentOrders[0].trade_type.startsWith('ALIPAY') ? '支付宝支付' : '微信支付'
|
||
} : null
|
||
}
|
||
});
|
||
} catch (error) {
|
||
console.error('检查用户支付状态失败:', error);
|
||
res.status(500).json({
|
||
success: false,
|
||
message: '检查支付状态失败'
|
||
});
|
||
}
|
||
});
|
||
|
||
/**
|
||
* 支付宝支付回调通知
|
||
* POST /api/payment/alipay/notify
|
||
*/
|
||
router.post('/alipay/notify', async (req, res) => {
|
||
try {
|
||
console.log('收到支付宝支付回调:', req.body);
|
||
|
||
// 验证签名
|
||
const isValid = alipayService.verifyNotifySign(req.body);
|
||
if (!isValid) {
|
||
console.error('支付宝回调签名验证失败');
|
||
return res.status(400).send('FAIL');
|
||
}
|
||
|
||
const {
|
||
out_trade_no: outTradeNo,
|
||
trade_no: transactionId,
|
||
trade_status: tradeStatus,
|
||
total_amount: totalAmount
|
||
} = req.body;
|
||
|
||
// 只处理支付成功的回调
|
||
if (tradeStatus === 'TRADE_SUCCESS') {
|
||
const db = getDB();
|
||
|
||
// 检查订单是否存在
|
||
const [orders] = await db.execute(
|
||
'SELECT id, user_id, status FROM payment_orders WHERE out_trade_no = ?',
|
||
[outTradeNo]
|
||
);
|
||
|
||
if (orders.length === 0) {
|
||
console.error('支付宝回调:订单不存在', outTradeNo);
|
||
return res.status(400).send('FAIL');
|
||
}
|
||
|
||
const order = orders[0];
|
||
|
||
// 如果订单已经处理过,直接返回成功
|
||
if (order.status === 'paid') {
|
||
console.log('支付宝回调:订单已处理', outTradeNo);
|
||
return res.send('SUCCESS');
|
||
}
|
||
|
||
// 更新订单状态
|
||
await alipayService.updatePaymentStatus(outTradeNo, {
|
||
status: 'paid',
|
||
transactionId,
|
||
paidAt: new Date()
|
||
});
|
||
|
||
console.log('支付宝支付成功处理完成:', {
|
||
outTradeNo,
|
||
transactionId,
|
||
userId: order.user_id
|
||
});
|
||
}
|
||
|
||
res.send('SUCCESS');
|
||
} catch (error) {
|
||
console.error('处理支付宝支付回调失败:', error);
|
||
res.status(500).send('FAIL');
|
||
}
|
||
});
|
||
|
||
/**
|
||
* 支付宝支付返回页面处理
|
||
* GET /api/payment/alipay/return
|
||
*/
|
||
router.get('/alipay/return', async (req, res) => {
|
||
try {
|
||
console.log('支付宝支付返回:', req.query);
|
||
|
||
// 验证签名
|
||
const isValid = alipayService.verifyNotifySign(req.query);
|
||
if (!isValid) {
|
||
console.error('支付宝返回签名验证失败');
|
||
return res.redirect('/payment/failed');
|
||
}
|
||
|
||
const { out_trade_no: outTradeNo } = req.query;
|
||
|
||
// 重定向到支付成功页面
|
||
res.redirect(`/payment/success?outTradeNo=${outTradeNo}`);
|
||
} catch (error) {
|
||
console.error('处理支付宝支付返回失败:', error);
|
||
res.redirect('/payment/failed');
|
||
}
|
||
});
|
||
|
||
module.exports = router; |