优化提现流程,新增用户确认模式以支持待用户确认的转账,更新相关API和数据库结构以确保数据一致性。同时,调整小程序界面以展示待确认收款信息,提升用户体验。
This commit is contained in:
53
app/api/withdraw/pending-confirm/route.ts
Normal file
53
app/api/withdraw/pending-confirm/route.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* 待确认收款列表 - 供小程序调起 wx.requestMerchantTransfer 使用
|
||||
* GET ?userId=xxx 返回当前用户 status=pending_confirm 且含 package_info 的提现记录,及 mch_id、app_id
|
||||
*/
|
||||
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { prisma } from '@/lib/prisma'
|
||||
import { getTransferMchAndAppId } from '@/lib/wechat-transfer'
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const userId = request.nextUrl.searchParams.get('userId')
|
||||
if (!userId) {
|
||||
return NextResponse.json({ success: false, message: '缺少 userId' }, { status: 400 })
|
||||
}
|
||||
|
||||
// 原始查询(数据库 ENUM 已包含 pending_confirm)
|
||||
const list = await prisma.$queryRaw<
|
||||
{ id: string; amount: unknown; package_info: string | null; created_at: Date }[]
|
||||
>`
|
||||
SELECT id, amount, package_info, created_at
|
||||
FROM withdrawals
|
||||
WHERE user_id = ${userId}
|
||||
AND status = 'pending_confirm'
|
||||
AND package_info IS NOT NULL
|
||||
ORDER BY created_at DESC
|
||||
`
|
||||
|
||||
const { mchId, appId } = getTransferMchAndAppId()
|
||||
|
||||
const items = list.map((w) => ({
|
||||
id: w.id,
|
||||
amount: Number(w.amount),
|
||||
package: w.package_info ?? '',
|
||||
created_at: w.created_at,
|
||||
}))
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: {
|
||||
list: items,
|
||||
mch_id: mchId,
|
||||
app_id: appId,
|
||||
},
|
||||
})
|
||||
} catch (e) {
|
||||
console.error('[Withdraw pending-confirm]', e)
|
||||
return NextResponse.json(
|
||||
{ success: false, message: '获取待确认列表失败' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
45
app/api/withdraw/records/route.ts
Normal file
45
app/api/withdraw/records/route.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* 提现记录列表 - 当前用户的全部提现记录(供小程序「提现记录」展示)
|
||||
* GET ?userId=xxx
|
||||
*/
|
||||
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { prisma } from '@/lib/prisma'
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const userId = request.nextUrl.searchParams.get('userId')
|
||||
if (!userId) {
|
||||
return NextResponse.json({ success: false, message: '缺少 userId' }, { status: 400 })
|
||||
}
|
||||
|
||||
const rows = await prisma.$queryRaw<
|
||||
{ id: string; amount: unknown; status: string; created_at: Date; processed_at: Date | null }[]
|
||||
>`
|
||||
SELECT id, amount, status, created_at, processed_at
|
||||
FROM withdrawals
|
||||
WHERE user_id = ${userId}
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 100
|
||||
`
|
||||
|
||||
const list = rows.map((r) => ({
|
||||
id: r.id,
|
||||
amount: Number(r.amount),
|
||||
status: r.status,
|
||||
created_at: r.created_at,
|
||||
processed_at: r.processed_at,
|
||||
}))
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: { list },
|
||||
})
|
||||
} catch (e) {
|
||||
console.error('[Withdraw records]', e)
|
||||
return NextResponse.json(
|
||||
{ success: false, message: '获取提现记录失败' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,10 @@
|
||||
/**
|
||||
* 提现API - 使用 Prisma ORM
|
||||
* 提现API - 使用 Prisma ORM + 原始查询(避免枚举未同步导致 500)
|
||||
* 用户提现到微信零钱
|
||||
*
|
||||
* Prisma 优势:
|
||||
* - 完全类型安全
|
||||
* - 自动防SQL注入
|
||||
* - 简化复杂查询
|
||||
*/
|
||||
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { prisma } from '@/lib/prisma'
|
||||
import { Decimal } from '@/lib/generated/prisma/runtime/library'
|
||||
|
||||
// 读取系统配置(使用 Prisma)
|
||||
async function getPrismaConfig(key: string): Promise<any> {
|
||||
@@ -127,19 +121,19 @@ export async function POST(request: NextRequest) {
|
||||
console.log('[Withdraw] 查询收益失败:', e)
|
||||
}
|
||||
|
||||
// 4. 已提现金额与待审核金额均以提现表为准(与分销页展示一致,避免 user.withdrawn_earnings 不同步导致负数或超额提现)
|
||||
const [pendingResult, successResult] = await Promise.all([
|
||||
prisma.withdrawals.aggregate({
|
||||
where: { user_id: userId, status: 'pending' },
|
||||
_sum: { amount: true }
|
||||
}),
|
||||
prisma.withdrawals.aggregate({
|
||||
where: { user_id: userId, status: 'success' },
|
||||
_sum: { amount: true }
|
||||
})
|
||||
// 4. 已提现金额与待审核金额(原始查询避免 withdrawals_status 枚举校验)
|
||||
const [pendingRows, successRows] = await Promise.all([
|
||||
prisma.$queryRaw<[{ sum_amount: unknown }]>`
|
||||
SELECT COALESCE(SUM(amount), 0) AS sum_amount FROM withdrawals
|
||||
WHERE user_id = ${userId} AND status = 'pending'
|
||||
`,
|
||||
prisma.$queryRaw<[{ sum_amount: unknown }]>`
|
||||
SELECT COALESCE(SUM(amount), 0) AS sum_amount FROM withdrawals
|
||||
WHERE user_id = ${userId} AND status = 'success'
|
||||
`
|
||||
])
|
||||
const withdrawnEarnings = Number(successResult._sum.amount || 0)
|
||||
const pendingWithdrawAmount = Number(pendingResult._sum.amount || 0)
|
||||
const pendingWithdrawAmount = Number((pendingRows[0] as { sum_amount: unknown })?.sum_amount ?? 0)
|
||||
const withdrawnEarnings = Number((successRows[0] as { sum_amount: unknown })?.sum_amount ?? 0)
|
||||
|
||||
// 5. 计算可提现金额(不低于 0)
|
||||
const availableAmount = Math.max(0, totalCommission - withdrawnEarnings - pendingWithdrawAmount)
|
||||
@@ -158,29 +152,22 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
}
|
||||
|
||||
// 7. 创建提现记录(使用 Prisma,无SQL注入风险)
|
||||
// 7. 创建提现记录(原始插入避免 status 枚举校验)
|
||||
const withdrawId = `W${Date.now()}`
|
||||
|
||||
const withdrawal = await prisma.withdrawals.create({
|
||||
data: {
|
||||
id: withdrawId,
|
||||
user_id: userId,
|
||||
amount: new Decimal(amount),
|
||||
status: 'pending',
|
||||
wechat_openid: openId,
|
||||
wechat_id: wechatId,
|
||||
created_at: new Date()
|
||||
}
|
||||
})
|
||||
|
||||
const amountNum = Number(amount)
|
||||
await prisma.$executeRaw`
|
||||
INSERT INTO withdrawals (id, user_id, amount, status, wechat_openid, wechat_id, created_at)
|
||||
VALUES (${withdrawId}, ${userId}, ${amountNum}, 'pending', ${openId}, ${wechatId}, NOW())
|
||||
`
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: '提现申请已提交,正在审核中,通过后会自动到账您的微信零钱',
|
||||
message: '提现申请已提交,通过后会在我的页面提醒您收款!',
|
||||
data: {
|
||||
withdrawId: withdrawal.id,
|
||||
amount: Number(withdrawal.amount),
|
||||
withdrawId,
|
||||
amount: amountNum,
|
||||
accountType: '微信',
|
||||
status: withdrawal.status
|
||||
status: 'pending'
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user