/** * 支付服务工具 * 统一管理支付相关功能 */ import { API_BASE } from '@/config/api.js'; /** * 模拟支付模式配置 * 设置为 true 时,所有支付都会使用模拟数据,不调用真实支付接口 */ export const MOCK_PAYMENT_MODE = false; export function mapOfficialVoiceDisplay(list) { const regionPrefixMap = { '湾区大叔': '台湾', '台湾小何': '台湾', '双节棍小哥': '台湾', '广州德哥': '广州', '浩宇小哥': '大陆', '湾湾小何': '台湾', '北京小爷': '北京', '京腔侃爷/Harmony': '北京', '林北浩儿': '台湾', '粤语小灿': '广东', '泉州子轩': '福建', '豫州子轩': '河南', '呆萌川妹': '四川', '广西远舟': '广西', '妹坨洁儿': '湖南' }; return (list || []).map(v => { if (!v) return v; const vt = v.voice_type || 'CLONE'; if (vt !== 'OFFICIAL') return v; const rawName = v.voice_name ? String(v.voice_name) : ''; const prefix = rawName && regionPrefixMap[rawName] ? regionPrefixMap[rawName] : ''; if (!prefix || !rawName) return v; if (rawName.indexOf(prefix + '-') === 0) return v; return { ...v, voice_name: `${prefix}-${rawName}` }; }); } /** * 服务类型映射(后端类型 -> 前端配置) */ const SERVICE_TYPE_MAPPING = { 'CREATE_VOICE': 'voice_clone', 'PHOTO_REVIVAL': 'photo_revival', 'VOLCENGINE_VIDEO': 'volcengine_video', 'SYNTHESIZE': 'tts_synthesis', 'VIDEO_CALL': 'video_call', 'AI_CALL': 'conversation' }; /** * 服务类型配置(默认值,会被后端数据覆盖) */ export const SERVICE_TYPES = { VOICE_CLONE: { type: 'voice_clone', backendType: 'CREATE_VOICE', name: '声音克隆', desc: '克隆您的声音,让AI学会您的音色', price: 0.00, freeTrialCount: 0 }, PHOTO_REVIVAL: { type: 'photo_revival', backendType: 'PHOTO_REVIVAL', name: '照片复活', desc: '让照片中的人开口说话', price: 0.00, freeTrialCount: 0 }, VOLCENGINE_VIDEO: { type: 'volcengine_video', backendType: 'VOLCENGINE_VIDEO', name: '火山视频复活', desc: '火山视频复活', price: 0.00, freeTrialCount: 0 }, TTS_SYNTHESIS: { type: 'tts_synthesis', backendType: 'SYNTHESIZE', name: '语音合成', desc: '使用已有音色合成语音', price: 0.00, freeTrialCount: 0 }, VIDEO_CALL: { type: 'video_call', backendType: 'VIDEO_CALL', name: 'AI视频通话', desc: 'AI视频通话', price: 0.00, freeTrialCount: 0 }, CONVERSATION: { type: 'conversation', backendType: 'AI_CALL', name: '实时对话', desc: '与AI进行实时语音对话', price: 0.00, freeTrialCount: 0 } }; // 缓存价格数据 let priceCache = null; let priceCacheTime = 0; const CACHE_DURATION = 5 * 60 * 1000; // 5分钟缓存 /** * 从后端获取服务价格列表 * @returns {Promise} */ export async function fetchServicePrices() { // 检查缓存 const now = Date.now(); if (priceCache && (now - priceCacheTime) < CACHE_DURATION) { console.log('[Payment] 使用缓存价格数据'); return priceCache; } console.log('[Payment] 开始获取服务价格,API地址:', `${API_BASE}/api/pay/prices`); return new Promise((resolve, reject) => { uni.request({ url: `${API_BASE}/api/pay/prices`, method: 'GET', success: (res) => { console.log('[Payment] 价格API响应:', res); if (res.statusCode === 200 && res.data) { priceCache = res.data; priceCacheTime = now; console.log('[Payment] 后端返回价格数据:', res.data); // 更新SERVICE_TYPES中的价格 let updateCount = 0; res.data.forEach(priceItem => { console.log('[Payment] 处理价格项:', priceItem); const frontendType = SERVICE_TYPE_MAPPING[priceItem.serviceType]; console.log('[Payment] 映射类型:', priceItem.serviceType, '->', frontendType); if (frontendType) { const serviceKey = Object.keys(SERVICE_TYPES).find( key => SERVICE_TYPES[key].type === frontendType ); if (serviceKey && SERVICE_TYPES[serviceKey]) { console.log('[Payment] 更新服务:', serviceKey, '价格:', priceItem.price, '免费次数:', priceItem.freeTrialCount); SERVICE_TYPES[serviceKey].price = priceItem.price; SERVICE_TYPES[serviceKey].freeTrialCount = priceItem.freeTrialCount || 0; SERVICE_TYPES[serviceKey].name = priceItem.serviceName; SERVICE_TYPES[serviceKey].desc = priceItem.description || SERVICE_TYPES[serviceKey].desc; updateCount++; } } else { console.warn('[Payment] 未找到映射的前端类型:', priceItem.serviceType); } }); console.log('[Payment] 价格更新完成,共更新', updateCount, '个服务'); console.log('[Payment] 最终SERVICE_TYPES:', JSON.stringify(SERVICE_TYPES, null, 2)); resolve(res.data); } else { console.error('[Payment] 获取价格失败,状态码:', res.statusCode); if (priceCache) { resolve(priceCache); return; } reject(new Error('获取价格失败')); } }, fail: (err) => { console.error('[Payment] 获取价格请求失败:', err); if (priceCache) { resolve(priceCache); return; } reject(err); } }); }); } /** * 生成订单号 */ function generateOrderNo() { const timestamp = Date.now(); const random = Math.floor(Math.random() * 10000).toString().padStart(4, '0'); return `ORD${timestamp}${random}`; } /** * 获取用户信息 */ function getUserInfo() { return { userId: uni.getStorageSync('userId') || '', token: uni.getStorageSync('token') || '' }; } async function fetchUsagePreview(frontendServiceType) { try { const { userId, token } = getUserInfo(); if (!userId) return null; const service = Object.values(SERVICE_TYPES).find(s => s.type === frontendServiceType); const backendServiceType = service ? service.backendType : frontendServiceType; return await new Promise((resolve) => { uni.request({ url: `${API_BASE}/api/pay/usage-preview?serviceType=${backendServiceType}`, method: 'GET', header: { 'X-User-Id': userId, 'Authorization': token ? `Bearer ${token}` : '' }, success: (res) => { if (res.statusCode === 200 && res.data && res.data.success) { resolve(res.data); return; } resolve(null); }, fail: () => resolve(null) }); }); } catch (e) { return null; } } /** * 后端资格校验:免费次数/补发次数/已支付 都视为可用。 * @param {string} frontendServiceType - 前端 service.type * @returns {Promise} - true 表示无需支付可直接使用 */ async function checkBackendEligibility(frontendServiceType) { try { const { userId, token } = getUserInfo(); if (!userId) return false; const service = Object.values(SERVICE_TYPES).find(s => s.type === frontendServiceType); const backendServiceType = service ? service.backendType : frontendServiceType; return await new Promise((resolve) => { uni.request({ url: `${API_BASE}/api/pay/check?userId=${userId}&serviceType=${backendServiceType}`, method: 'GET', header: { 'X-User-Id': userId, 'Authorization': token ? `Bearer ${token}` : '' }, success: (res) => { // 按次付费场景:只有“明确剩余次数>0”才视为可用。 // 兼容后端可能返回的字段: // - paid: boolean // - remainingTotal / remaining / remainingCount / remainingTimes // - freeTrialRemaining / freeTrialLeft if (res.statusCode === 200 && res.data && typeof res.data.paid === 'boolean') { const data = res.data || {}; console.log('[Payment] /api/pay/check 响应:', backendServiceType, data); if (data.paid === false) { resolve(false); return; } const remainingTotal = (typeof data.remainingTotal === 'number') ? data.remainingTotal : (typeof data.remaining === 'number') ? data.remaining : (typeof data.remainingCount === 'number') ? data.remainingCount : (typeof data.remainingTimes === 'number') ? data.remainingTimes : null; const freeTrialRemaining = (typeof data.freeTrialRemaining === 'number') ? data.freeTrialRemaining : (typeof data.freeTrialLeft === 'number') ? data.freeTrialLeft : null; // 有任何一种剩余次数>0,则允许跳过支付 if ((typeof remainingTotal === 'number' && remainingTotal > 0) || (typeof freeTrialRemaining === 'number' && freeTrialRemaining > 0)) { resolve(true); return; } // paid=true 但没有明确剩余次数(或<=0),视为需要付费 resolve(false); return; } resolve(false); }, fail: () => resolve(false) }); }); } catch (e) { console.error('[Payment] 后端资格校验异常:', e); return false; } } /** * 创建订单 * @param {string} serviceType - 服务类型 * @param {object} extraData - 额外数据 * @returns {Promise} */ export async function createOrder(serviceType, extraData = {}) { try { // 先获取最新价格 await fetchServicePrices(); // 获取服务配置 const service = Object.values(SERVICE_TYPES).find(s => s.type === serviceType); if (!service) { throw new Error('无效的服务类型'); } const orderNo = generateOrderNo(); console.log('[Payment] 创建订单:', { orderNo, serviceType, serviceName: service.name, amount: service.price }); return { orderNo, serviceType, serviceName: service.name, amount: service.price, service, ...extraData }; } catch (error) { console.error('[Payment] 创建订单失败:', error); throw error; } } /** * 获取支付渠道 * @returns {string} 'wechat' | 'alipay' */ function getPaymentChannel() { // #ifdef MP-WEIXIN return 'wechat'; // #endif // #ifdef MP-ALIPAY return 'alipay'; // #endif // #ifdef APP-PLUS // App环境:可以根据用户选择或默认使用微信 // 这里默认使用微信,也可以让用户选择 return uni.getStorageSync('preferred_payment') || 'wechat'; // #endif // 默认返回微信 return 'wechat'; } /** * 创建后端支付订单 * @param {string} serviceType - 服务类型(前端类型) * @param {number} userId - 用户ID * @returns {Promise} */ export async function createBackendOrder(serviceType, userId) { // 模拟支付模式:直接返回模拟订单数据 if (MOCK_PAYMENT_MODE) { console.log('[Payment] 模拟支付模式:创建模拟订单'); const service = Object.values(SERVICE_TYPES).find(s => s.type === serviceType); const mockOrderNo = 'MOCK_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9); return new Promise((resolve) => { setTimeout(() => { resolve({ orderNo: mockOrderNo, userId: userId, serviceType: service ? service.backendType : serviceType, serviceName: service ? service.name : '未知服务', amount: service ? service.price : 0, status: 'PENDING', paymentChannel: 'mock', qrCodeUrl: 'MOCK_QR_CODE_' + mockOrderNo, createdAt: new Date().toISOString() }); }, 500); // 模拟网络延迟 }); } // 真实支付模式 const channel = getPaymentChannel(); // 将前端类型转换为后端类型 const service = Object.values(SERVICE_TYPES).find(s => s.type === serviceType); const backendServiceType = service ? service.backendType : serviceType; console.log('[Payment] 服务类型转换:', serviceType, '->', backendServiceType); // 获取用户标识用于小程序支付 let bizId = null; if (channel === 'wechat') { // #ifdef MP-WEIXIN const openid = uni.getStorageSync('wx_openid'); console.log('[Payment] wx_openid:', openid); if (openid) { bizId = 'wx_openid_' + openid; } else { console.error('[Payment] 缺少wx_openid,无法创建微信小程序支付订单'); return Promise.reject(new Error('缺少openid,请先退出并重新微信登录')); } // #endif // #ifdef APP-PLUS // App微信支付不需要openid bizId = 'wx_app'; // #endif } else if (channel === 'alipay') { const alipayUserId = uni.getStorageSync('alipay_user_id'); if (alipayUserId) { bizId = 'alipay_user_' + alipayUserId; } } console.log('[Payment] 下单参数:', { userId, serviceType: backendServiceType, paymentChannel: channel, bizId }); return new Promise((resolve, reject) => { uni.request({ url: `${API_BASE}/api/pay/orders`, method: 'POST', header: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${uni.getStorageSync('token') || ''}` }, data: { userId: userId, serviceType: backendServiceType, paymentChannel: channel, bizId: bizId }, success: (res) => { if (res.statusCode === 200 && res.data) { console.log('[Payment] 后端订单创建成功:', res.data); resolve(res.data); } else { console.error('[Payment] 后端订单创建失败:', { statusCode: res.statusCode, data: res.data, header: res.header }); if (res.data && res.data.message) { console.error('[Payment] 后端错误信息:', res.data.message); } reject(new Error(res.data?.message || '创建订单失败')); } }, fail: (err) => { console.error('[Payment] 创建订单请求失败:', err); reject(err); } }); }); } /** * 执行微信支付(支持小程序和App) * @param {object} orderData - 订单数据 * @returns {Promise} */ function executeWechatPayment(orderData) { return new Promise((resolve, reject) => { // 模拟支付模式:直接返回成功 if (MOCK_PAYMENT_MODE) { console.log('[Payment] 模拟支付模式:模拟微信支付成功'); setTimeout(() => { resolve({ success: true, orderNo: orderData.orderNo, payTime: new Date().toISOString(), message: '支付成功(模拟)' }); }, 1000); // 模拟1秒支付延迟 return; } // #ifdef MP-WEIXIN // 微信小程序支付 uni.requestPayment({ timeStamp: orderData.timeStamp || String(Date.now()), nonceStr: orderData.nonceStr || '', package: orderData.package || '', signType: orderData.signType || 'RSA', paySign: orderData.paySign || '', success: (res) => { console.log('[Payment] 微信支付成功:', res); uni.request({ url: `${API_BASE}/api/pay/orders/${orderData.orderNo}/sync/wechat`, method: 'POST', header: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${uni.getStorageSync('token') || ''}` }, success: (syncRes) => { if (syncRes.statusCode === 200) { console.log('[Payment] 订单同步成功:', syncRes.data); resolve({ success: true, orderNo: orderData.orderNo, payTime: new Date().toISOString(), message: '支付成功' }); } else { console.error('[Payment] 订单同步失败:', syncRes); reject(new Error(syncRes.data?.message || '支付成功但订单同步失败')); } }, fail: (err) => { console.error('[Payment] 订单同步请求失败:', err); reject(new Error('支付成功但订单同步请求失败')); } }); }, fail: (err) => { console.error('[Payment] 微信支付失败:', err); if (err.errMsg && err.errMsg.includes('cancel')) { reject(new Error('用户取消支付')); } else { reject(new Error(err.errMsg || '支付失败')); } } }); // #endif // #ifdef APP-PLUS uni.requestPayment({ provider: 'wxpay', orderInfo: orderData.orderInfo || '', success: (res) => { console.log('[Payment] App微信支付成功:', res); resolve({ success: true, orderNo: orderData.orderNo, payTime: new Date().toISOString(), message: '支付成功' }); }, fail: (err) => { console.error('[Payment] App微信支付失败:', err); if (err.errMsg && err.errMsg.includes('cancel')) { reject(new Error('用户取消支付')); } else { reject(new Error(err.errMsg || '支付失败')); } } }); // #endif // #if !defined(MP-WEIXIN) && !defined(APP-PLUS) reject(new Error('当前环境不支持微信支付')); // #endif }); } /** * 执行支付宝支付(支持小程序和App) * @param {object} orderData - 订单数据 * @returns {Promise} */ function executeAlipayPayment(orderData) { return new Promise((resolve, reject) => { // 模拟支付模式:直接返回成功 if (MOCK_PAYMENT_MODE) { console.log('[Payment] 模拟支付模式:模拟支付宝支付成功'); setTimeout(() => { resolve({ success: true, orderNo: orderData.orderNo, payTime: new Date().toISOString(), message: '支付成功(模拟)' }); }, 1000); // 模拟1秒支付延迟 return; } // #ifdef MP-ALIPAY // 支付宝小程序支付 my.tradePay({ tradeNO: orderData.tradeNo || '', success: (res) => { console.log('[Payment] 支付宝支付成功:', res); resolve({ success: true, orderNo: orderData.orderNo, payTime: new Date().toISOString(), message: '支付成功' }); }, fail: (err) => { console.error('[Payment] 支付宝支付失败:', err); if (err.resultCode === '6001') { reject(new Error('用户取消支付')); } else { reject(new Error(err.memo || '支付失败')); } } }); // #endif // #ifdef APP-PLUS // App环境:暂时使用模拟支付(开发测试用) console.log('[Payment] App环境 - 使用模拟支付'); setTimeout(() => { console.log('[Payment] 模拟支付宝支付成功'); resolve({ success: true, orderNo: orderData.orderNo, payTime: new Date().toISOString(), message: '支付成功(模拟)' }); }, 1000); // 模拟1秒支付延迟 // 真实支付代码(暂时注释) // uni.requestPayment({ // provider: 'alipay', // orderInfo: orderData.orderInfo || orderData.tradeNo || '', // success: (res) => { // console.log('[Payment] App支付宝支付成功:', res); // resolve({ // success: true, // orderNo: orderData.orderNo, // payTime: new Date().toISOString(), // message: '支付成功' // }); // }, // fail: (err) => { // console.error('[Payment] App支付宝支付失败:', err); // if (err.errMsg && err.errMsg.includes('cancel')) { // reject(new Error('用户取消支付')); // } else { // reject(new Error(err.errMsg || '支付失败')); // } // } // }); // #endif // #if !defined(MP-ALIPAY) && !defined(APP-PLUS) reject(new Error('当前环境不支持支付宝支付')); // #endif }); } /** * 执行支付(真实版本) * @param {string} serviceType - 服务类型 * @param {number} userId - 用户ID * @returns {Promise} */ export async function executePayment(serviceType, userId) { // 优先校验后端是否已具备使用资格(免费次数/补发/已支付) try { const eligible = await checkBackendEligibility(serviceType); if (eligible) { console.log('[Payment] 后端校验通过,跳过支付:', serviceType); return { success: true, message: '已具备使用资格,无需支付', skipPayment: true }; } } catch (e) { console.error('[Payment] 后端资格校验失败(忽略继续走支付):', e); } // 先获取服务价格 await fetchServicePrices(); const service = Object.values(SERVICE_TYPES).find(s => s.type === serviceType); // 如果价格为0,直接返回成功,跳过支付 if (service && service.price === 0) { console.log('[Payment] 服务价格为0,跳过支付流程'); const orderNo = generateOrderNo(); const result = { success: true, orderNo: orderNo, payTime: new Date().toISOString(), message: '免费服务,无需支付', free: true }; uni.showToast({ title: '免费使用', icon: 'success', duration: 1500 }); console.log('[Payment] 免费服务,直接返回成功:', result); return result; } // #ifdef APP-PLUS // APP环境:使用真实支付流程 try { uni.showLoading({ title: '创建订单中...', mask: true }); const orderData = await createBackendOrder(serviceType, userId); uni.showLoading({ title: '正在调起支付...', mask: true }); const channel = getPaymentChannel(); let paymentResult; if (channel === 'wechat') { paymentResult = await executeWechatPayment(orderData); } else if (channel === 'alipay') { paymentResult = await executeAlipayPayment(orderData); } else { throw new Error('不支持的支付渠道'); } uni.hideLoading(); return paymentResult; } catch (error) { uni.hideLoading(); throw error; } // #endif // #ifndef APP-PLUS // 小程序环境:使用真实支付流程 try { uni.showLoading({ title: '创建订单中...', mask: true }); // 1. 创建后端订单 const orderData = await createBackendOrder(serviceType, userId); uni.showLoading({ title: '正在调起支付...', mask: true }); // 2. 根据渠道执行支付 const channel = getPaymentChannel(); let paymentResult; if (channel === 'wechat') { paymentResult = await executeWechatPayment(orderData); } else if (channel === 'alipay') { paymentResult = await executeAlipayPayment(orderData); } else { throw new Error('不支持的支付渠道'); } uni.hideLoading(); return paymentResult; } catch (error) { uni.hideLoading(); throw error; } // #endif } /** * 检查订单支付状态(真实版本) * @param {string} orderNo - 订单号 * @returns {Promise} */ export function checkPaymentStatus(orderNo) { return new Promise((resolve, reject) => { uni.request({ url: `${API_BASE}/api/pay/orders/${orderNo}`, method: 'GET', header: { 'Authorization': `Bearer ${uni.getStorageSync('token') || ''}` }, success: (res) => { if (res.statusCode === 200 && res.data) { console.log('[Payment] 查询支付状态成功:', res.data); resolve({ success: true, orderNo: res.data.orderNo, status: res.data.status, payTime: res.data.paidAt }); } else { reject(new Error('查询订单状态失败')); } }, fail: (err) => { console.error('[Payment] 查询订单状态失败:', err); reject(err); } }); }); } /** * 完整的支付流程 * @param {string} serviceType - 服务类型 * @param {object} options - 配置选项 * @returns {Promise} */ export async function processPayment(serviceType, options = {}) { const { extraData = {}, onOrderCreated = null, onPaymentSuccess = null, onPaymentFailed = null } = options; try { // 1. 创建订单 console.log('[Payment] 创建订单:', serviceType); const orderData = await createOrder(serviceType, extraData); if (onOrderCreated) { onOrderCreated(orderData); } // 2. 执行支付 console.log('[Payment] 执行支付:', serviceType); const userId = getUserInfo().userId; const paymentResult = await executePayment(serviceType, userId); // 3. 支付成功 console.log('[Payment] 支付成功:', paymentResult); if (onPaymentSuccess) { onPaymentSuccess(paymentResult); } return { success: true, orderNo: orderData.orderNo, ...paymentResult }; } catch (error) { console.error('[Payment] 支付流程失败:', error); if (onPaymentFailed) { onPaymentFailed(error); } throw error; } } /** * 显示支付弹窗并处理支付 * 这是一个高级封装,配合PaymentModal组件使用 * @param {object} vm - Vue实例 * @param {string} serviceType - 服务类型 * @param {function} onSuccess - 支付成功回调 * @param {function} onFailed - 支付失败回调 */ export async function showPaymentModal(vm, serviceType, onSuccess, onFailed) { // 先获取最新价格 try { await fetchServicePrices(); } catch (e) { // ignore } // 优先校验后端是否已具备使用资格(免费次数/补发/已支付),避免弹支付窗 try { const eligible = await checkBackendEligibility(serviceType); if (eligible) { console.log('[Payment] 后端校验通过,跳过支付弹窗:', serviceType); try { const preview = await fetchUsagePreview(serviceType); if (preview && preview.consumeType === 'FREE_TRIAL') { uni.showToast({ title: '本次使用免费次数', icon: 'none', duration: 1500 }); } } catch (e) { // ignore } if (onSuccess) { onSuccess({ success: true, skipPayment: true, message: '已具备使用资格,无需支付' }); } return; } } catch (e) { console.error('[Payment] 后端资格校验失败(忽略继续弹窗):', e); } // 获取服务配置 const service = Object.values(SERVICE_TYPES).find(s => s.type === serviceType); if (!service) { const error = new Error('无效的服务类型'); console.error('[Payment] 显示支付弹窗失败:', error); uni.showToast({ title: '无效的服务类型', icon: 'none' }); if (onFailed) { onFailed(error); } return; } // 如果价格为0,直接执行支付(跳过弹窗) if (service.price === 0) { console.log('[Payment] 服务价格为0,跳过支付弹窗,直接执行'); try { const userId = getUserInfo().userId; const result = await executePayment(serviceType, userId); // 调用成功回调 if (onSuccess) { onSuccess(result); } } catch (error) { console.error('[Payment] 免费服务执行失败:', error); if (onFailed) { onFailed(error); } } return; } // 价格不为0,显示支付弹窗 createOrder(serviceType) .then(orderData => { // 设置弹窗数据 vm.paymentModalData = { show: true, serviceType: service.type, serviceName: service.name, serviceDesc: service.desc, price: service.price, orderNo: orderData.orderNo }; // 保存回调 vm._paymentOnSuccess = onSuccess; vm._paymentOnFailed = onFailed; }) .catch(error => { console.error('[Payment] 创建订单失败:', error); uni.showToast({ title: error.message || '创建订单失败', icon: 'none' }); if (onFailed) { onFailed(error); } }); } /** * 处理支付确认(在PaymentModal的confirm事件中调用) * @param {object} vm - Vue实例 * @param {object} paymentData - 支付数据 */ export async function handlePaymentConfirm(vm, paymentData) { try { // 执行支付 const userId = getUserInfo().userId; const result = await executePayment(paymentData.serviceType, userId); // 通知PaymentModal支付成功 if (vm.$refs.paymentModal) { vm.$refs.paymentModal.paymentSuccess(); } // 关闭弹窗 vm.paymentModalData.show = false; // 显示成功提示 uni.showToast({ title: '支付成功', icon: 'success' }); // 调用成功回调 if (vm._paymentOnSuccess) { vm._paymentOnSuccess(result); } if (vm._paymentResolve) { vm._paymentResolve(result); } } catch (error) { console.error('[Payment] 支付失败:', error); // 通知PaymentModal支付失败 if (vm.$refs.paymentModal) { vm.$refs.paymentModal.paymentFailed(error); } // 显示错误提示 uni.showToast({ title: error.message || '支付失败', icon: 'none' }); // 调用失败回调 if (vm._paymentOnFailed) { vm._paymentOnFailed(error); } if (vm._paymentReject) { vm._paymentReject(error); } } } export default { SERVICE_TYPES, createOrder, executePayment, checkPaymentStatus, processPayment, showPaymentModal, handlePaymentConfirm };