const crypto = require('crypto') const config = require('../config.json') const { normalizePayBaseUrl } = require('./PaymentClient') const { getRuntimeConfig } = require('./RuntimeConfig') const DEFAULT_PAYMENT_METHODS = [ { type: 'alipay', name: '支付宝' }, { type: 'wxpay', name: '微信支付' } ] async function getPaymentMethods() { const paymentConfig = await getRuntimeConfig('pay', { required: false, defaultValue: { methods: DEFAULT_PAYMENT_METHODS } }) const methods = paymentConfig?.methods if (!Array.isArray(methods)) { return DEFAULT_PAYMENT_METHODS } return methods .filter(method => method && method.enabled !== false && typeof method.type === 'string' && method.type.trim()) .map(method => ({ type: method.type.trim(), name: String(method.name || method.type).trim() })) } async function isSupportedPaymentMethod(payType) { return (await getPaymentMethods()).some(method => method.type === payType) } function generatePaymentSign(params, key) { const query = Object.keys(params) .sort() .map(keyName => `${keyName}=${params[keyName]}`) .join('&') + key return crypto.createHash('md5').update(query, 'utf8').digest('hex') } async function buildPaymentSession({ orderId, gatewayOrderNo = orderId, payType, goodsName, price, deviceType }) { const paymentConfig = await getRuntimeConfig('pay') if (!paymentConfig.pid || !paymentConfig.url || !paymentConfig.key || !paymentConfig.return_url) { throw new Error('支付配置错误,请联系管理员') } if (!await isSupportedPaymentMethod(payType)) { throw new Error('不支持的支付方式') } const isUniapp = deviceType === 'RunForge Uniapp Client' const returnBaseUrl = isUniapp ? paymentConfig.uni_return_url : paymentConfig.return_url if (!returnBaseUrl) { throw new Error('支付返回地址配置错误,请联系管理员') } const payData = { pid: paymentConfig.pid, type: payType, out_trade_no: gatewayOrderNo, notify_url: `${config.url}/Order/CallBack`, return_url: `${returnBaseUrl}${orderId}`, name: goodsName, money: String(price) } payData.sign = generatePaymentSign(payData, paymentConfig.key) payData.sign_type = 'MD5' return { payUrl: `${normalizePayBaseUrl(paymentConfig.url)}/submit.php`, payData, // 客户端收到后应以 payData 创建并自动提交一个 POST 表单,进入支付网关。 autoSubmit: true } } module.exports = { buildPaymentSession, getPaymentMethods, isSupportedPaymentMethod }