118 lines
3.0 KiB
TypeScript
118 lines
3.0 KiB
TypeScript
|
|
export interface PaymentOrder {
|
||
|
|
orderId: string
|
||
|
|
userId: string
|
||
|
|
type: "section" | "fullbook"
|
||
|
|
sectionId?: string
|
||
|
|
sectionTitle?: string
|
||
|
|
amount: number
|
||
|
|
paymentMethod: "wechat" | "alipay" | "usdt" | "paypal"
|
||
|
|
referralCode?: string
|
||
|
|
status: "pending" | "completed" | "failed" | "refunded"
|
||
|
|
createdAt: string
|
||
|
|
expireAt: string
|
||
|
|
transactionId?: string
|
||
|
|
completedAt?: string
|
||
|
|
}
|
||
|
|
|
||
|
|
export class PaymentService {
|
||
|
|
/**
|
||
|
|
* Create a new payment order
|
||
|
|
*/
|
||
|
|
static async createOrder(params: {
|
||
|
|
userId: string
|
||
|
|
type: "section" | "fullbook"
|
||
|
|
sectionId?: string
|
||
|
|
sectionTitle?: string
|
||
|
|
amount: number
|
||
|
|
paymentMethod: string
|
||
|
|
referralCode?: string
|
||
|
|
}): Promise<PaymentOrder> {
|
||
|
|
const response = await fetch("/api/payment/create-order", {
|
||
|
|
method: "POST",
|
||
|
|
headers: { "Content-Type": "application/json" },
|
||
|
|
body: JSON.stringify(params),
|
||
|
|
})
|
||
|
|
|
||
|
|
const result = await response.json()
|
||
|
|
if (result.code !== 0) {
|
||
|
|
throw new Error(result.message || "创建订单失败")
|
||
|
|
}
|
||
|
|
|
||
|
|
return result.data
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Verify payment completion
|
||
|
|
*/
|
||
|
|
static async verifyPayment(orderId: string, transactionId?: string): Promise<boolean> {
|
||
|
|
const response = await fetch("/api/payment/verify", {
|
||
|
|
method: "POST",
|
||
|
|
headers: { "Content-Type": "application/json" },
|
||
|
|
body: JSON.stringify({ orderId, transactionId }),
|
||
|
|
})
|
||
|
|
|
||
|
|
const result = await response.json()
|
||
|
|
return result.code === 0 && result.data.status === "completed"
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get user orders
|
||
|
|
*/
|
||
|
|
static async getUserOrders(userId: string): Promise<PaymentOrder[]> {
|
||
|
|
const response = await fetch(`/api/orders?userId=${userId}`)
|
||
|
|
const result = await response.json()
|
||
|
|
|
||
|
|
if (result.code !== 0) {
|
||
|
|
throw new Error(result.message || "获取订单失败")
|
||
|
|
}
|
||
|
|
|
||
|
|
return result.data
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get payment gateway config
|
||
|
|
*/
|
||
|
|
static getPaymentConfig(method: "wechat" | "alipay" | "usdt" | "paypal") {
|
||
|
|
// In production, fetch from settings API
|
||
|
|
// For now, use localStorage
|
||
|
|
const settings = JSON.parse(localStorage.getItem("settings") || "{}")
|
||
|
|
return settings.paymentMethods?.[method] || {}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Generate payment QR code URL
|
||
|
|
*/
|
||
|
|
static getPaymentQRCode(method: "wechat" | "alipay", amount: number, orderId: string): string {
|
||
|
|
const config = this.getPaymentConfig(method)
|
||
|
|
|
||
|
|
// If it's a redirect URL, return it directly
|
||
|
|
if (
|
||
|
|
config.qrCode?.startsWith("http") ||
|
||
|
|
config.qrCode?.startsWith("weixin://") ||
|
||
|
|
config.qrCode?.startsWith("alipays://")
|
||
|
|
) {
|
||
|
|
return config.qrCode
|
||
|
|
}
|
||
|
|
|
||
|
|
// Otherwise return the QR code image
|
||
|
|
return config.qrCode || ""
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Open payment app (Wechat/Alipay)
|
||
|
|
*/
|
||
|
|
static openPaymentApp(method: "wechat" | "alipay", orderId: string): boolean {
|
||
|
|
const config = this.getPaymentConfig(method)
|
||
|
|
const redirectUrl = config.qrCode
|
||
|
|
|
||
|
|
if (!redirectUrl) {
|
||
|
|
console.error("[v0] No payment URL configured for", method)
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
// Open URL in new window/tab
|
||
|
|
window.open(redirectUrl, "_blank")
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
}
|