Files
soul-yongping/app/api/withdraw/route.ts

236 lines
7.0 KiB
TypeScript
Raw Normal View History

/**
* API
*
*/
import { NextRequest, NextResponse } from 'next/server'
import { query } from '@/lib/db'
import crypto from 'crypto'
// 微信支付配置(使用真实配置)
const WECHAT_PAY_CONFIG = {
mchId: process.env.WECHAT_MCH_ID || '1318592501',
appId: process.env.WECHAT_APPID || 'wxb8bbb2b10dec74aa', // 小程序AppID
apiKey: process.env.WECHAT_API_KEY || 'wx3e31b068be59ddc131b068be59ddc2' // 商户API密钥
}
// 最低提现金额
const MIN_WITHDRAW_AMOUNT = 10
// 生成订单号
function generateOrderNo(): string {
return 'WD' + Date.now().toString() + Math.random().toString(36).substr(2, 6).toUpperCase()
}
// 生成签名
function generateSign(params: Record<string, any>, apiKey: string): string {
const sortedKeys = Object.keys(params).sort()
const stringA = sortedKeys
.filter(key => params[key] !== '' && params[key] !== undefined)
.map(key => `${key}=${params[key]}`)
.join('&')
const stringSignTemp = stringA + '&key=' + apiKey
return crypto.createHash('md5').update(stringSignTemp).digest('hex').toUpperCase()
}
/**
* POST -
*/
export async function POST(request: NextRequest) {
try {
const body = await request.json()
const { userId, amount } = body
if (!userId) {
return NextResponse.json({
success: false,
error: '用户ID不能为空'
}, { status: 400 })
}
// 获取用户信息
const users = await query('SELECT * FROM users WHERE id = ?', [userId]) as any[]
if (users.length === 0) {
return NextResponse.json({
success: false,
error: '用户不存在'
}, { status: 404 })
}
const user = users[0]
// 检查用户是否绑定了openId微信提现必需
if (!user.open_id) {
return NextResponse.json({
success: false,
error: '请先绑定微信账号',
needBind: true
}, { status: 400 })
}
// 获取可提现金额
const pendingEarnings = parseFloat(user.pending_earnings) || 0
const withdrawAmount = amount || pendingEarnings
if (withdrawAmount < MIN_WITHDRAW_AMOUNT) {
return NextResponse.json({
success: false,
error: `最低提现金额为${MIN_WITHDRAW_AMOUNT}元,当前可提现${pendingEarnings}`
}, { status: 400 })
}
if (withdrawAmount > pendingEarnings) {
return NextResponse.json({
success: false,
error: `余额不足,当前可提现${pendingEarnings}`
}, { status: 400 })
}
// 创建提现记录
const withdrawId = generateOrderNo()
await query(`
INSERT INTO withdrawals (id, user_id, amount, status, wechat_openid)
VALUES (?, ?, ?, 'pending', ?)
`, [withdrawId, userId, withdrawAmount, user.open_id])
// 尝试调用微信企业付款
let wxPayResult = null
let paySuccess = false
try {
// 企业付款参数
const params: Record<string, any> = {
mch_appid: WECHAT_PAY_CONFIG.appId,
mchid: WECHAT_PAY_CONFIG.mchId,
nonce_str: crypto.randomBytes(16).toString('hex'),
partner_trade_no: withdrawId,
openid: user.open_id,
check_name: 'NO_CHECK',
amount: Math.round(withdrawAmount * 100), // 转换为分
desc: 'Soul创业派对-分销佣金提现',
spbill_create_ip: '127.0.0.1'
}
params.sign = generateSign(params, WECHAT_PAY_CONFIG.apiKey)
// 注意:实际企业付款需要使用证书,这里简化处理
// 生产环境需要使用微信支付SDK或完整的证书配置
console.log('[Withdraw] 企业付款参数:', params)
// 模拟成功实际需要调用微信API
// 在实际生产环境中这里应该使用微信支付SDK进行企业付款
paySuccess = true
wxPayResult = {
payment_no: 'WX' + Date.now(),
payment_time: new Date().toISOString()
}
} catch (wxError: any) {
console.error('[Withdraw] 微信支付失败:', wxError)
// 更新提现记录为失败
await query(`
UPDATE withdrawals
SET status = 'failed', error_message = ?, processed_at = NOW()
WHERE id = ?
`, [wxError.message, withdrawId])
}
if (paySuccess) {
// 更新提现记录为成功
await query(`
UPDATE withdrawals
SET status = 'success', transaction_id = ?, processed_at = NOW()
WHERE id = ?
`, [wxPayResult?.payment_no, withdrawId])
// 更新用户余额
await query(`
UPDATE users
SET pending_earnings = pending_earnings - ?,
withdrawn_earnings = COALESCE(withdrawn_earnings, 0) + ?,
earnings = COALESCE(earnings, 0) + ?
WHERE id = ?
`, [withdrawAmount, withdrawAmount, withdrawAmount, userId])
return NextResponse.json({
success: true,
message: '提现成功,已到账微信零钱',
data: {
withdrawId,
amount: withdrawAmount,
transactionId: wxPayResult?.payment_no,
processedAt: wxPayResult?.payment_time
}
})
} else {
return NextResponse.json({
success: false,
error: '提现处理中,请稍后查看到账情况',
withdrawId
})
}
} catch (error) {
console.error('[Withdraw] 错误:', error)
return NextResponse.json({
success: false,
error: '提现失败: ' + (error as Error).message
}, { status: 500 })
}
}
/**
* GET -
*/
export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url)
const userId = searchParams.get('userId')
if (!userId) {
return NextResponse.json({
success: false,
error: '用户ID不能为空'
}, { status: 400 })
}
try {
// 获取用户余额
const users = await query('SELECT pending_earnings, withdrawn_earnings, earnings FROM users WHERE id = ?', [userId]) as any[]
if (users.length === 0) {
return NextResponse.json({
success: false,
error: '用户不存在'
}, { status: 404 })
}
const user = users[0]
// 获取提现记录
const records = await query(`
SELECT id, amount, status, transaction_id, error_message, created_at, processed_at
FROM withdrawals
WHERE user_id = ?
ORDER BY created_at DESC
LIMIT 50
`, [userId]) as any[]
return NextResponse.json({
success: true,
data: {
pendingEarnings: parseFloat(user.pending_earnings) || 0,
withdrawnEarnings: parseFloat(user.withdrawn_earnings) || 0,
totalEarnings: parseFloat(user.earnings) || 0,
minWithdrawAmount: MIN_WITHDRAW_AMOUNT,
records
}
})
} catch (error) {
console.error('[Withdraw] GET错误:', error)
return NextResponse.json({
success: false,
error: '获取提现记录失败: ' + (error as Error).message
}, { status: 500 })
}
}