import crypto from "crypto" export interface AlipayConfig { appId: string partnerId: string key: string returnUrl: string notifyUrl: string } export class AlipayService { constructor(private config: AlipayConfig) {} // 创建支付宝订单 createOrder(params: { outTradeNo: string subject: string totalAmount: number body?: string }) { const orderInfo = { app_id: this.config.appId, method: "alipay.trade.wap.pay", format: "JSON", charset: "utf-8", sign_type: "MD5", timestamp: new Date().toISOString().slice(0, 19).replace("T", " "), version: "1.0", notify_url: this.config.notifyUrl, return_url: this.config.returnUrl, biz_content: JSON.stringify({ out_trade_no: params.outTradeNo, product_code: "QUICK_WAP_WAY", total_amount: params.totalAmount.toFixed(2), subject: params.subject, body: params.body || params.subject, }), } const sign = this.generateSign(orderInfo) return { ...orderInfo, sign, paymentUrl: this.buildPaymentUrl(orderInfo, sign), } } // 生成签名 generateSign(params: Record): string { const sortedKeys = Object.keys(params).sort() const signString = sortedKeys .filter((key) => params[key] && key !== "sign") .map((key) => `${key}=${params[key]}`) .join("&") const signWithKey = `${signString}${this.config.key}` return crypto.createHash("md5").update(signWithKey, "utf8").digest("hex") } // 验证回调签名 verifySign(params: Record): boolean { const receivedSign = params.sign if (!receivedSign) return false const calculatedSign = this.generateSign(params) return receivedSign.toLowerCase() === calculatedSign.toLowerCase() } // 构建支付URL private buildPaymentUrl(params: Record, sign: string): string { const gateway = "https://openapi.alipay.com/gateway.do" const queryParams = new URLSearchParams({ ...params, sign }) return `${gateway}?${queryParams.toString()}` } }