diff --git a/components/MapComponent.vue b/components/MapComponent.vue index f002f3b..1263e37 100644 --- a/components/MapComponent.vue +++ b/components/MapComponent.vue @@ -3,40 +3,88 @@ - - - - - - @@ -508,15 +556,16 @@ const handleSearch = () => { overflow: hidden; display: flex; flex-direction: column; - + // #ifdef H5 - height:78vh; + height: 78vh; // #endif // #ifdef MP-WEIXIN height: 72vh; // #endif + &.full-width { width: 100%; margin: 0; @@ -682,6 +731,7 @@ const handleSearch = () => { justify-content: center; gap: 8rpx; z-index: 2; + pointer-events: none; .indicator-dot { width: 12rpx; diff --git a/components/MapComponentAlipay.vue b/components/MapComponentAlipay.vue new file mode 100644 index 0000000..4b40eec --- /dev/null +++ b/components/MapComponentAlipay.vue @@ -0,0 +1,687 @@ + + + + + + diff --git a/components/OrderItemCard.vue b/components/OrderItemCard.vue index 3468a39..7278633 100644 --- a/components/OrderItemCard.vue +++ b/components/OrderItemCard.vue @@ -22,6 +22,12 @@ {{ $t('order.memberOrder') }} + + {{ $t('order.aliPay') }} + + + {{ $t('order.antomPay') }} + {{ $t('order.wxPay') }} | diff --git a/config/api/coupon.js b/config/api/coupon.js index 5041c62..ba594be 100644 --- a/config/api/coupon.js +++ b/config/api/coupon.js @@ -9,12 +9,14 @@ export const getCouponsByPosition = (positionId) => { } // 创建优惠券支付订单 -export const createCouponPayment = (couponId) => { +export const createCouponPayment = (couponId, paymentPlatform) => { return request({ url: '/app/coupon/pay', method: 'post', data: { - couponId + couponId, + // 支付平台类型:WECHAT / ALIPAY / ANTOM(不传则后端默认 WECHAT) + ...(paymentPlatform ? { paymentPlatform } : {}) } }) } diff --git a/config/api/member.js b/config/api/member.js index fbc9d10..af31314 100644 --- a/config/api/member.js +++ b/config/api/member.js @@ -1,12 +1,14 @@ import request from '../http' // 创建会员卡支付订单 -export const createMemberCardPayment = (memberCardId) => { +export const createMemberCardPayment = (memberCardId, paymentPlatform) => { return request({ url: '/app/member/pay', method: 'post', data: { - memberCardId + memberCardId, + // 支付平台类型:WECHAT / ALIPAY / ANTOM(不传则后端默认 WECHAT) + ...(paymentPlatform ? { paymentPlatform } : {}) } }) } diff --git a/config/api/order.js b/config/api/order.js index 1b2b027..cd9e741 100644 --- a/config/api/order.js +++ b/config/api/order.js @@ -126,6 +126,15 @@ export const createWxPayment = (orderNo) => { }) } +// 创建支付宝支付订单(租借押金 H5 支付) +// 对应文档《支付宝接口文档》:GET /app/ali-payment/create/{orderNo} +export const createAliPayment = (orderNo) => { + return request({ + url: `/app/ali-payment/create/${orderNo}`, + method: 'get' + }) +} + // 获取正在使用中的订单 export const getInUseOrder = () => { return request({ @@ -150,6 +159,15 @@ export const getWxPaymentStatus = (orderNo) => { }) } +// 查询支付宝支付状态 +// 对应文档:GET /app/ali-payment/status/{orderNo} +export const getAliPaymentStatus = (orderNo) => { + return request({ + url: `/app/ali-payment/status/${orderNo}`, + method: 'get' + }) +} + // ==================== Antom 支付相关接口 ==================== // 创建 Antom H5 支付订单 diff --git a/config/api/product.js b/config/api/product.js index 0408e5f..7386f81 100644 --- a/config/api/product.js +++ b/config/api/product.js @@ -33,14 +33,10 @@ export const getProductDetail = (id) => { } /** - * 创建商品支付订单 - * @param {Object} data - 订单数据 - * @param {Array} data.items - 订单项列表 [{skuId, quantity}] - * @param {string} data.receiverName - 收件人姓名 - * @param {string} data.receiverPhone - 收件人手机号 - * @param {string} data.receiverAddress - 收件人详细地址 - * @param {string} data.remark - 用户备注(可选) - * @returns {Promise} 微信支付参数 + * 创建商品支付订单(多支付平台) + * 对应《商品购买多支付平台方案》: + * paymentPlatform: WECHAT / ALIPAY / ANTOM + * 其他字段见文档 */ export const createProductOrder = (data) => { return request({ diff --git a/config/api/user.js b/config/api/user.js index 1d63bf2..8ea14db 100644 --- a/config/api/user.js +++ b/config/api/user.js @@ -1,7 +1,7 @@ import request from '../http' import { URL, appid } from '../url' -// 用户登录 +// 旧登录接口(兼容保留,后端将逐步废弃) export const login = (data) => { return request({ url: '/app/user/login', @@ -10,6 +10,22 @@ export const login = (data) => { }) } +// 统一快捷登录接口 /app/user/quickLogin +// 对应文档《快捷登录最终方案》中的 QuickLoginDto: +// loginType: WECHAT / ALIPAY / SMS +// appid: 平台应用ID +// openId: 第三方 openId(微信必传) +// code: 授权码(微信手机号授权码 / 支付宝 authCode) +// phonenumber: 短信登录手机号 +// smsCode: 短信验证码 +export const quickLogin = (data) => { + return request({ + url: '/app/user/quickLogin', + method: 'post', + data + }) +} + // 发送验证码 export const sendVerifyCode = (phonenumber) => { return request({ @@ -144,3 +160,13 @@ export const getWxUserPhoneNumber = (data) => { }) } +// 获取支付宝用户手机号(复用同一后端接口,由后端按 appid / 参数结构区分平台) +// 期望后端返回:{ code:200, data:{ phoneNumber: 'xxx' } } +export const getAliUserPhoneNumber = (data) => { + return request({ + url: '/app/user/alipay/getPhone', + method: 'post', + data + }) +} + diff --git a/config/console.js b/config/console.js index 2c254eb..5111fc2 100644 --- a/config/console.js +++ b/config/console.js @@ -6,7 +6,7 @@ // 配置项:true 表示打印日志,false 表示不打印日志 export const CONSOLE_CONFIG = { // 是否启用 console.log - enableLog: false, + enableLog: true, // 是否启用 console.warn enableWarn: false, // 是否启用 console.error diff --git a/config/http.js b/config/http.js index 9234f5b..851d261 100644 --- a/config/http.js +++ b/config/http.js @@ -1,8 +1,15 @@ import { URL, - appid + appid, + ZFBappid } from './url' +// 根据运行平台选择正确的小程序 appid(后端通常依赖该 header 做平台识别) +let platformAppid = appid +// #ifdef MP-ALIPAY +platformAppid = ZFBappid +// #endif + // 获取多语言翻译文本 const getLoadingText = () => { try { @@ -31,7 +38,7 @@ const request = (option) => { header: { "Content-Type": option.headers && option.headers["Content-Type"] ? option.headers["Content-Type"] : (option.method && option.method.toUpperCase() === 'POST' ? 'application/json' : 'application/x-www-form-urlencoded'), ...option.headers, - 'appid': appid, + 'appid': platformAppid, 'Authorization': "Bearer " + uni.getStorageSync('token'), 'Clientid': uni.getStorageSync('client_id'), 'Content-Language': (uni.getStorageSync('language') || 'zh-CN').replace(/-/g, '_') diff --git a/config/url.js b/config/url.js index 542c40a..beae7bc 100644 --- a/config/url.js +++ b/config/url.js @@ -1,7 +1,7 @@ // export const URL = "https://my.gxfs123.com/api" //正式服务器-弃用 // export const URL = "https://manager.fdzpower.com/api" //正式服务器 export const URL = "https://fansdev.gxfs123.com/api" //测试服务器 -// export const URL = "http://192.168.5.123:8080" //本地调试 +// export const URL = "http://192.168.5.64:8080" //本地调试 // export const URL = "http://127.0.0.1:8080" //本地调试 export const appid = "wx2165f0be356ae7a9" //微信小程序appid diff --git a/locale/en-US.js b/locale/en-US.js index b1e910b..f21bfac 100644 --- a/locale/en-US.js +++ b/locale/en-US.js @@ -211,6 +211,8 @@ export default { depositFree: 'Deposit-free', whitelistOrder: 'Whitelist Order', memberOrder: 'Member Order', + aliPay: 'AliPay', + antomPay: 'Antom Pay', wxPay: 'WeChat Pay', depositPay: 'Deposit Pay', paymentInProgress: 'Payment in Progress', @@ -307,6 +309,8 @@ export default { cooperation: 'Partner', settings: 'Settings', userAgreement: 'Terms', + settinguserAgreement:'Terms', + settinguserprivacyPolicy:'Privacy', privacyPolicy: 'Privacy', version: 'v', logout: 'Logout', diff --git a/locale/id-ID.js b/locale/id-ID.js index d6b206c..03fa34a 100644 --- a/locale/id-ID.js +++ b/locale/id-ID.js @@ -211,6 +211,8 @@ export default { depositFree: 'Sewa Tanpa Deposit', whitelistOrder: 'Pesanan Whitelist', memberOrder: 'Pesanan Anggota', + aliPay: 'Alipay', + antomPay: 'Antom Pay', wxPay: 'Pembayaran WeChat', depositPay: 'Sewa dengan Deposit', paymentInProgress: 'Sedang membayar', @@ -307,6 +309,8 @@ export default { cooperation: 'Kerja Sama dan Keanggotaan', settings: 'Pengaturan', userAgreement: '《Perjanjian Pengguna》', + settinguserAgreement:'Perjanjian Pengguna', + settinguserprivacyPolicy:'Kebijakan Privasi', privacyPolicy: '《Kebijakan Privasi》', version: 'v', logout: 'Keluar', diff --git a/locale/zh-CN.js b/locale/zh-CN.js index 663be47..c7ba755 100644 --- a/locale/zh-CN.js +++ b/locale/zh-CN.js @@ -84,7 +84,7 @@ export default { scanToUse: '扫码使用', personalCenter: '个人中心', useGuide: '使用指南', - buyDevice: '充电宝定制', + buyDevice: '产品定制', navigate: '导航', relocate: '重新定位', search: '搜索', @@ -210,6 +210,8 @@ export default { depositFree: '免押租借', whitelistOrder: '白名单订单', memberOrder: '会员订单', + aliPay: '支付宝支付', + antomPay: '海外支付', wxPay: '微信支付', depositPay: '押金租借', paymentInProgress: '支付中', @@ -306,7 +308,9 @@ export default { cooperation: '合作加盟', settings: '设置', userAgreement: '《用户协议》', + settinguserAgreement: '用户协议', privacyPolicy: '《隐私政策》', + settinguserprivacyPolicy: '隐私政策', version: 'v', logout: '退出登录', confirmLogout: '确认退出登录?', diff --git a/manifest.json b/manifest.json index 64ca6b5..41c0899 100644 --- a/manifest.json +++ b/manifest.json @@ -69,12 +69,9 @@ "requiredPrivateInfos" : [ "getLocation", "chooseLocation" ] }, "mp-alipay" : { - "component2":true, - "transpile":[ - "uview-ui", - "vue-i18n" - ], - "skia":true, + "component2" : true, + "transpile" : [ "uview-ui", "vue-i18n" ], + "skia" : true, "usingComponents" : true, "appid" : "2021006117693332", "unipush" : { diff --git a/pages/device/detail.vue b/pages/device/detail.vue index f678ba2..e77bfa2 100644 --- a/pages/device/detail.vue +++ b/pages/device/detail.vue @@ -91,7 +91,7 @@ + @click="handleRent"> {{ hasActiveOrder ? $t('order.returnDevice') : getRentButtonText() }} @@ -176,6 +176,8 @@ const phoneNumber = ref('') const showPhoneAuthPopup = ref(false) const isWechatMiniProgram = ref(false) + const isAlipayMiniProgram = ref(false) + const isH5 = ref(false) // 生命周期 onLoad 钩子 onLoad(async (options) => { @@ -193,13 +195,27 @@ uni.setNavigationBarTitle({ title: t('device.deviceInfo') }) - // 检测当前运行环境 + // 检测当前运行环境:微信小程序 / 支付宝小程序 / H5 // #ifdef MP-WEIXIN isWechatMiniProgram.value = true + isAlipayMiniProgram.value = false + isH5.value = false + // #endif + // #ifdef MP-ALIPAY + isWechatMiniProgram.value = false + isAlipayMiniProgram.value = true + isH5.value = false // #endif // #ifdef H5 isWechatMiniProgram.value = false + isAlipayMiniProgram.value = false + isH5.value = true // #endif + console.log('当前运行环境:', { + isWechatMiniProgram: isWechatMiniProgram.value, + isAlipayMiniProgram: isAlipayMiniProgram.value, + isH5: isH5.value + }) await checkUserPhone() await fetchDeviceInfo() }) @@ -437,7 +453,7 @@ } // 处理租借操作 - const handleRent = (payWay) => { + const handleRent = () => { if (!isLoggedIn.value) { showLoginTip() return @@ -448,9 +464,22 @@ showPhoneAuthPopup.value = true return } - - // 提交订单 - submitRentOrder(payWay) + + // 根据运行环境选择不同的租借/支付流程 + // 微信小程序:走微信支付分免押租借 + if (isWechatMiniProgram.value) { + submitRentOrder('wx-score-pay') + return + } + + // 支付宝小程序:走押金租借,后续在支付页内调起支付宝支付 + if (isAlipayMiniProgram.value) { + submitRentOrder('wx-pay') + return + } + + // H5 等其他环境:统一走押金租借,支付页内根据平台选择支付方式(Antom 等) + submitRentOrder('wx-pay') } // 获取价格单位文本 @@ -603,7 +632,7 @@ // 跳转到订单支付页面 uni.redirectTo({ - url: `/pages/order/payment?orderId=${order.orderId}&packagePrice=${packagePrice}&totalAmount=${totalAmount}&depositAmount=${deposit}${deviceInfo.value && deviceInfo.value.feeConfig ? '&feeConfig=' + encodeURIComponent(deviceInfo.value.feeConfig) : ''}` + url: `/subPackages/order/payment?orderId=${order.orderId}&packagePrice=${packagePrice}&totalAmount=${totalAmount}&depositAmount=${deposit}${deviceInfo.value && deviceInfo.value.feeConfig ? '&feeConfig=' + encodeURIComponent(deviceInfo.value.feeConfig) : ''}` }) } else if (payWay == 'wx-score-pay') { diff --git a/pages/index/index.vue b/pages/index/index.vue index 4520ca0..afa181d 100644 --- a/pages/index/index.vue +++ b/pages/index/index.vue @@ -1,14 +1,14 @@ @@ -340,6 +398,7 @@ const showSkuPopup = ref(false) const showAddressPopup = ref(false) const showAddressDisplay = ref(false) // 地址展示弹窗 + const showRegionPicker = ref(false) // 支付宝地区选择弹窗 // 计算是否已有地址 const hasAddress = computed(() => { @@ -489,6 +548,45 @@ addressForm.value.districtCode = district.code } + // 支付宝小程序 picker-view 列变化 + const onAliRegionChange = (e) => { + const newVal = e.detail.value || [] + const oldVal = regionIndexes.value || [] + + // 找出发生变化的列 + let column = -1 + for (let i = 0; i < newVal.length; i++) { + if (newVal[i] !== oldVal[i]) { + column = i + break + } + } + + if (column !== -1) { + onRegionColumnChange({ + detail: { + column, + value: newVal[column] + } + }) + } + } + + // 关闭支付宝地区弹窗 + const closeRegionPicker = () => { + showRegionPicker.value = false + } + + // 支付宝地区选择“确定” + const confirmAliRegion = () => { + onRegionChange({ + detail: { + value: regionIndexes.value + } + }) + closeRegionPicker() + } + // 获取用户收货地址 const fetchUserAddress = async () => { try { @@ -767,7 +865,7 @@ }) } - // 创建订单并支付 + // 创建订单并支付(接入商品多支付平台方案:微信 / 支付宝,小程序端) const createOrder = async () => { try { uni.showLoading({ @@ -782,13 +880,24 @@ savedAddress.value.receiverAddress : `${addressForm.value.province}${addressForm.value.city}${addressForm.value.district}${addressForm.value.receiverAddress}` + // 根据当前运行环境确定支付平台 + let paymentPlatform = 'WECHAT' // 默认微信 + // #ifdef MP-ALIPAY + paymentPlatform = 'ALIPAY' + // #endif + // #ifdef H5 + // H5 预留 Antom 支付,这里暂时仍按微信处理,如需接入可改为 ANTOM 并补充 paymentType / osType + paymentPlatform = 'WECHAT' + // #endif + const orderData = { skuId: selectedSku.value.skuId, - quantity:quantity.value, + quantity: quantity.value, receiverName: addressData.receiverName, receiverPhone: addressData.receiverPhone, receiverAddress: fullAddress, // 传递完整地址(省市区+详细地址) - remark: addressForm.value.remark || '' + remark: addressForm.value.remark || '', + paymentPlatform // WECHAT / ALIPAY /(预留)ANTOM } console.log('创建订单数据:', orderData) @@ -800,11 +909,12 @@ if (res && res.code === 200 && res.data) { uni.hideLoading() - // 调用微信支付 + // 统一获取平台订单号(商品统一支付订单号) + const outOrderNo = res.data.OutOrderNo || res.data.outOrderNo + + // ====================== 微信小程序支付 ====================== + // #ifdef MP-WEIXIN const payParams = res.data - // 保存订单ID,用于取消订单 - const orderId = payParams.OutOrderNo || res.data.OutOrderNo - uni.requestPayment({ timeStamp: payParams.timeStamp, nonceStr: payParams.nonceStr, @@ -831,26 +941,18 @@ }, fail: async (payErr) => { console.error('支付失败:', payErr) - + // 判断是用户取消还是支付失败 if (payErr.errMsg && payErr.errMsg.includes('cancel')) { - // 用户取消支付,调用取消订单接口 + // 用户取消支付,这里预留调用取消订单接口 try { - // uni.showLoading({ - // title: '正在取消订单...', - // mask: true - // }) - - // await cancelProductOrder(orderId) - - uni.hideLoading() + // await cancelProductOrder(outOrderNo) uni.showToast({ title: '支付已取消', icon: 'none' }) } catch (cancelError) { console.error('取消订单失败:', cancelError) - uni.hideLoading() uni.showToast({ title: '支付已取消', icon: 'none' @@ -865,6 +967,62 @@ } } }) + // #endif + + // ====================== 支付宝小程序支付 ====================== + // #ifdef MP-ALIPAY + console.log(res.data,'支付宝支付参数'); + + const tradeNO = res.data.tradeNo + if (!tradeNO) { + uni.showToast({ + title: '未获取到支付宝支付参数', + icon: 'none' + }) + return + } + + my.tradePay({ + tradeNO, + success: (payRes) => { + console.log('支付宝支付结果:', payRes) + if (payRes.resultCode === '9000') { + uni.showToast({ + title: '支付成功', + icon: 'success', + duration: 2000 + }) + + resetForm() + + setTimeout(() => { + uni.switchTab({ + url: '/subPackages/business/device-orderList' + }) + }, 2000) + } else { + uni.showToast({ + title: '支付失败,请重试', + icon: 'none' + }) + } + }, + fail: () => { + uni.showToast({ + title: '支付失败,请重试', + icon: 'none' + }) + } + }) + // #endif + + // ====================== H5 环境(预留 Antom 支付) ====================== + // #ifdef H5 + uni.showToast({ + title: '当前环境暂不支持购买,请使用微信或支付宝小程序', + icon: 'none' + }) + // #endif } else { uni.hideLoading() uni.showToast({ diff --git a/subPackages/business/device-orderList.vue b/subPackages/business/device-orderList.vue index 1fb3a0f..b813e0f 100644 --- a/subPackages/business/device-orderList.vue +++ b/subPackages/business/device-orderList.vue @@ -335,25 +335,40 @@ navigateToOrderDetail(order); }; - // 立即支付 + // 立即支付(对齐 device-goods.vue,多平台支付) const handlePayment = async (order) => { try { uni.showLoading({ title: '正在创建支付...', mask: true }); - console.log(order); - - // 调用后端创建微信支付订单接口(使用订单号) - // const res = await createWxPayment(order.orderNo); - const res = await createProductOrder({orderNo:order.orderNo}); + console.log('订单列表立即支付,订单信息:', order); + + // 根据当前运行环境确定支付平台(与 device-goods.vue 保持一致) + let paymentPlatform = 'WECHAT'; // 默认微信 + // #ifdef MP-ALIPAY + paymentPlatform = 'ALIPAY'; + // #endif + // #ifdef H5 + // H5 预留 Antom 支付,这里暂时仍按微信处理,如需接入可改为 ANTOM 并补充 paymentType / osType + paymentPlatform = 'WECHAT'; + // #endif + + // 使用商品多支付平台统一下单接口,对已有订单进行支付 + const res = await createProductOrder({ + orderNo: order.orderNo, + paymentPlatform + }); if (res && res.code === 200 && res.data) { uni.hideLoading(); - + + // 统一获取平台订单号(商品统一支付订单号) + const outOrderNo = res.data.OutOrderNo || res.data.outOrderNo; + + // ====================== 微信小程序支付 ====================== + // #ifdef MP-WEIXIN const payParams = res.data; - - // 调用微信支付 uni.requestPayment({ timeStamp: payParams.timeStamp, nonceStr: payParams.nonceStr, @@ -367,25 +382,25 @@ icon: 'success', duration: 2000 }); - + // 刷新订单列表 const statusArray = orderStatusTabs[currentTab.value].status; const statusValue = statusArray.length === 0 ? undefined : statusArray[0]; await loadOrderList(statusValue); }, - fail: async (err) => { - console.error('支付失败:', err); - + fail: async (payErr) => { + console.error('支付失败:', payErr); + // 判断是用户取消还是支付失败 - if (err.errMsg && err.errMsg.includes('cancel')) { - // 用户取消支付,调用取消订单接口 + if (payErr.errMsg && payErr.errMsg.includes('cancel')) { + // 用户取消支付,这里预留调用取消订单接口 try { - // await cancelProductOrder(order.id || order.orderId); - // uni.showToast({ - // title: '支付已取消', - // icon: 'none' - // }); - + // await cancelProductOrder(outOrderNo || order.orderNo); + uni.showToast({ + title: '支付已取消', + icon: 'none' + }); + // 刷新订单列表 const statusArray = orderStatusTabs[currentTab.value].status; const statusValue = statusArray.length === 0 ? undefined : statusArray[0]; @@ -406,6 +421,59 @@ } } }); + // #endif + + // ====================== 支付宝小程序支付 ====================== + // #ifdef MP-ALIPAY + console.log(res.data, '支付宝支付参数'); + + const tradeNO = res.data.tradeNo || res.data.tradeNO; + if (!tradeNO) { + uni.showToast({ + title: '未获取到支付宝支付参数', + icon: 'none' + }); + return; + } + + my.tradePay({ + tradeNO, + success: async (payRes) => { + console.log('支付宝支付结果:', payRes); + if (payRes.resultCode === '9000') { + uni.showToast({ + title: '支付成功', + icon: 'success', + duration: 2000 + }); + + // 支付成功后刷新订单列表 + const statusArray = orderStatusTabs[currentTab.value].status; + const statusValue = statusArray.length === 0 ? undefined : statusArray[0]; + await loadOrderList(statusValue); + } else { + uni.showToast({ + title: '支付失败,请重试', + icon: 'none' + }); + } + }, + fail: () => { + uni.showToast({ + title: '支付失败,请重试', + icon: 'none' + }); + } + }); + // #endif + + // ====================== H5 环境(预留 Antom 支付) ====================== + // #ifdef H5 + uni.showToast({ + title: '当前环境暂不支持购买,请使用微信或支付宝小程序', + icon: 'none' + }); + // #endif } else { uni.hideLoading(); uni.showToast({ diff --git a/subPackages/business/purchase/index.vue b/subPackages/business/purchase/index.vue index bbe14bc..75529b3 100644 --- a/subPackages/business/purchase/index.vue +++ b/subPackages/business/purchase/index.vue @@ -176,9 +176,6 @@ import { createCouponPayment, cancelCouponPayment } from '@/config/api/coupon.js' -// import { -// cancelMemberCardPayment -// } from '@/config/api/member.js' import { createMemberCardPayment, getMemberCardsByPosition, @@ -353,7 +350,48 @@ const selectProduct = (product) => { const orderNo = ref('') -// 处理购买 +// 获取当前支付平台(前端维度) +const getPaymentPlatform = () => { + // 小程序环境 + // #ifdef MP-WEIXIN + return 'WECHAT' + // #endif + // #ifdef MP-ALIPAY + return 'ALIPAY' + // #endif + // H5 默认使用 ANTOM + // #ifdef H5 + return 'ANTOM' + // #endif + + return 'WECHAT' +} + +// 支付宝 tradePay 兼容:优先 tradeNO,其次 orderStr +const alipayTradePay = ({ tradeNo, orderStr, onSuccess, onFail }) => { + // #ifdef MP-ALIPAY + const tradeNO = tradeNo + if (tradeNO) { + my.tradePay({ + tradeNO, + success: onSuccess, + fail: onFail + }) + return + } + if (orderStr) { + my.tradePay({ + orderStr, + success: onSuccess, + fail: onFail + }) + return + } + // #endif + onFail && onFail(new Error('未获取到支付宝支付参数')) +} + +// 处理购买(会员卡 / 优惠券),内部使用商品多支付平台方案下的统一思路 const handleBuy = async () => { if (!selectedProduct.value) { uni.showToast({ @@ -363,63 +401,89 @@ const handleBuy = async () => { return } - // 会员卡购买 + const paymentPlatform = getPaymentPlatform() + + // 会员卡购买(按接口文档:POST /app/member/pay) if (currentTab.value === 'card') { try { uni.showLoading({ title: '正在创建订单...' }) - const res = await createMemberCardPayment(selectedProduct.value.id) + const res = await createMemberCardPayment(selectedProduct.value.id, paymentPlatform) uni.hideLoading() if (res.code === 200 && res.data) { - - orderNo.value = res.data.OutOrderNo; - // 调起微信支付 - uni.requestPayment({ - timeStamp: res.data.timeStamp, - nonceStr: res.data.nonceStr, - package: res.data.packageValue || res.data.package, - signType: res.data.signType || 'MD5', - paySign: res.data.paySign, - success: (payRes) => { - uni.showToast({ - title: '支付成功', - icon: 'success' - }) - // 支付成功后,跳转到我的会员卡页面 - setTimeout(() => { - uni.navigateTo({ - url: '/subPackages/business/my-card' - }) - }, 1500) - }, - fail: (err) => { - console.error('支付失败:', err) - console.log('支付失败详细信息:', err.errMsg.includes('cancel')); - if (err.errMsg && err.errMsg.includes('cancel')) { - if (orderNo.value) { - cancelMemberCardPayment(orderNo.value) - .then(cancelRes => { - console.log('取消支付订单成功:', cancelRes); - }) - .catch(cancelErr => { - console.error('取消支付订单失败:', cancelErr); - }); + // 不同平台分别发起支付(字段按文档) + // 微信小程序 + // #ifdef MP-WEIXIN + if (paymentPlatform === 'WECHAT') { + // 会员卡订单号:OutOrderNo(文档) + orderNo.value = res.data.OutOrderNo + uni.requestPayment({ + timeStamp: res.data.timeStamp, + nonceStr: res.data.nonceStr, + package: res.data.package, + signType: res.data.signType || 'MD5', + paySign: res.data.paySign, + success: () => { + uni.showToast({ title: '支付成功', icon: 'success' }) + setTimeout(() => { + uni.navigateTo({ url: '/subPackages/business/my-card' }) + }, 1500) + }, + fail: (err) => { + console.error('支付失败:', err) + if (err.errMsg && err.errMsg.includes('cancel')) { + // 取消支付(本项目取消接口走 device 侧 cancel) + orderNo.value && cancelMemberCardPayment(orderNo.value).catch(() => {}) + uni.showToast({ title: '已取消支付', icon: 'none' }) + } else { + uni.showToast({ title: '支付失败', icon: 'none' }) } - uni.showToast({ - title: '已取消支付', - icon: 'none' - }) - } else { - uni.showToast({ - title: '支付失败', - icon: 'none' - }) } + }) + return + } + // #endif + + // 支付宝小程序 + // #ifdef MP-ALIPAY + if (paymentPlatform === 'ALIPAY') { + // 文档返回:tradeNo / outTradeNo;也兼容 orderStr + const tradeNo = res.data.tradeNo || res.data.tradeNO + const payForm = res.data.payForm || res.data.orderStr + alipayTradePay({ + tradeNo, + orderStr: payForm, + onSuccess: (payRes) => { + if (payRes.resultCode === '9000') { + uni.showToast({ title: '支付成功', icon: 'success' }) + setTimeout(() => { + uni.navigateTo({ url: '/subPackages/business/my-card' }) + }, 1500) + } else { + uni.showToast({ title: '支付失败', icon: 'none' }) + } + }, + onFail: () => { + uni.showToast({ title: '支付失败', icon: 'none' }) + } + }) + return + } + // #endif + + // H5 + Antom(文档里 Antom 预留,当前后端可能返回 cashierUrl / h5Url 之一) + // #ifdef H5 + if (paymentPlatform === 'ANTOM') { + const cashierUrl = res.data.cashierUrl || res.data.h5Url + if (cashierUrl) { + window.location.href = cashierUrl + return } - }) + } + // #endif } else { uni.showToast({ title: res.msg || '创建订单失败', @@ -437,62 +501,83 @@ const handleBuy = async () => { return } - // 优惠券购买 + // 优惠券购买(按接口文档:POST /app/coupon/pay) if (currentTab.value === 'coupon') { try { uni.showLoading({ title: '正在创建订单...' }) - const res = await createCouponPayment(selectedProduct.value.couponId) + const res = await createCouponPayment(selectedProduct.value.couponId, paymentPlatform) uni.hideLoading() if (res.code === 200 && res.data) { - // 调起微信支付 - uni.requestPayment({ - timeStamp: res.data.timeStamp, - nonceStr: res.data.nonceStr, - package: res.data.packageValue || res.data.package, - signType: res.data.signType || 'MD5', - paySign: res.data.paySign, - success: (payRes) => { - uni.showToast({ - title: '支付成功', - icon: 'success' - }) - // 支付成功后,跳转到我的优惠券页面 - setTimeout(() => { - uni.navigateTo({ - url: '/subPackages/business/my-coupon' - }) - }, 1500) - }, - fail: (err) => { - console.error('支付失败:', err) - if (err.errMsg && err.errMsg.includes('cancel')) { - // 用户取消支付,调用取消接口 - const orderNo = res.data.OutOrderNo; - if (orderNo) { - cancelCouponPayment(orderNo) - .then(cancelRes => { - console.log('取消支付订单成功:', cancelRes); - }) - .catch(cancelErr => { - console.error('取消支付订单失败:', cancelErr); - }); + // 微信小程序 + // #ifdef MP-WEIXIN + if (paymentPlatform === 'WECHAT') { + uni.requestPayment({ + timeStamp: res.data.timeStamp, + nonceStr: res.data.nonceStr, + package: res.data.package, + signType: res.data.signType || 'MD5', + paySign: res.data.paySign, + success: () => { + uni.showToast({ title: '支付成功', icon: 'success' }) + setTimeout(() => { + uni.navigateTo({ url: '/subPackages/business/my-coupon' }) + }, 1500) + }, + fail: (err) => { + console.error('支付失败:', err) + if (err.errMsg && err.errMsg.includes('cancel')) { + const outOrderNo = res.data.OutOrderNo || res.data.outOrderNo + outOrderNo && cancelCouponPayment(outOrderNo).catch(() => {}) + uni.showToast({ title: '已取消支付', icon: 'none' }) + } else { + uni.showToast({ title: '支付失败', icon: 'none' }) } - uni.showToast({ - title: '已取消支付', - icon: 'none' - }) - } else { - uni.showToast({ - title: '支付失败', - icon: 'none' - }) } + }) + return + } + // #endif + + // 支付宝小程序 + // #ifdef MP-ALIPAY + if (paymentPlatform === 'ALIPAY') { + const tradeNo = res.data.tradeNo || res.data.tradeNO + const payForm = res.data.payForm || res.data.orderStr + alipayTradePay({ + tradeNo, + orderStr: payForm, + onSuccess: (payRes) => { + if (payRes.resultCode === '9000') { + uni.showToast({ title: '支付成功', icon: 'success' }) + setTimeout(() => { + uni.navigateTo({ url: '/subPackages/business/my-coupon' }) + }, 1500) + } else { + uni.showToast({ title: '支付失败', icon: 'none' }) + } + }, + onFail: () => { + uni.showToast({ title: '支付失败', icon: 'none' }) + } + }) + return + } + // #endif + + // H5 + Antom + // #ifdef H5 + if (paymentPlatform === 'ANTOM') { + const cashierUrl = res.data.cashierUrl || res.data.h5Url + if (cashierUrl) { + window.location.href = cashierUrl + return } - }) + } + // #endif } else { uni.showToast({ title: res.msg || '创建订单失败', diff --git a/subPackages/order/payment.vue b/subPackages/order/payment.vue index 14a3651..f3bf1e2 100644 --- a/subPackages/order/payment.vue +++ b/subPackages/order/payment.vue @@ -78,6 +78,10 @@ } from '@dcloudio/uni-app' import { queryById, + createWxPayment, + getWxPaymentStatus, + createAliPayment, + getAliPaymentStatus, createAntomPayment, getAntomPaymentMethods, getAntomPaymentStatus @@ -107,9 +111,9 @@ const countdown = ref(15 * 60) // 15分钟 = 900秒 let countdownTimer = null - // 支付方式相关 + // 支付方式相关(微信/支付宝/H5-Antom 多平台) const paymentMethods = ref([]) - const selectedPaymentMethod = ref('ALIPAY') // 默认选择支付宝 + const selectedPaymentMethod = ref('WECHAT') // 默认微信 // 地点名称(可以从设备信息中获取,这里先用默认值) const locationName = ref('澎创办公室') @@ -197,11 +201,11 @@ deviceNo.value = orderData.deviceNo; await loadDeviceInfo(); await loadPaymentMethods(); - // #ifdef H5 + // 如果订单状态是等待支付,启动相应的支付状态轮询 if(orderInfo.value.orderStatus=='waiting_for_payment'){ + // 使用当前选中的支付方式类型进行轮询 startPaymentStatusPolling(); } - // #endif } else { throw new Error(t('order.getOrderFailed')) } @@ -253,35 +257,46 @@ } } - // 加载支付方式列表 + // 加载支付方式列表(根据平台决定可选项) const loadPaymentMethods = async () => { - if (!orderInfo.value.orderNo) return; + const methods = [] - try { - const osType = getOsType(); - console.log('当前系统类型:', osType); + // 小程序环境下:微信 / 支付宝 + // #ifdef MP-WEIXIN + methods.push({ paymentMethodType: 'WECHAT', paymentMethodName: '微信支付' }) + // #endif + // #ifdef MP-ALIPAY + methods.push({ paymentMethodType: 'ALIPAY', paymentMethodName: '支付宝支付' }) + // #endif - const res = await getAntomPaymentMethods(orderInfo.value.orderNo, osType); - if (res.code === 200 && res.data && res.data.paymentOptions) { - paymentMethods.value = res.data.paymentOptions; - console.log('支付方式列表:', paymentMethods.value); - // 如果有支付方式,默认选择第一个 - if (paymentMethods.value.length > 0) { - selectedPaymentMethod.value = paymentMethods.value[0].paymentMethodType; + // H5 环境:使用 Antom 聚合支付(多通道) + // #ifdef H5 + if (orderInfo.value.orderNo) { + try { + const osType = getOsType(); + const res = await getAntomPaymentMethods(orderInfo.value.orderNo, osType); + if (res.code === 200 && res.data && res.data.paymentOptions) { + res.data.paymentOptions.forEach(item => { + methods.push({ + paymentMethodType: item.paymentMethodType, + paymentMethodName: item.paymentMethodName || item.paymentMethodType + }); + }); } + } catch (error) { + console.error('获取 Antom 支付方式失败:', error); } - } catch (error) { - console.error('获取支付方式失败:', error); - // 如果获取失败,使用默认支付方式 - paymentMethods.value = [{ - paymentMethodType: 'ALIPAY', - paymentMethodName: '支付宝' - }, - { - paymentMethodType: 'WECHATPAY', - paymentMethodName: '微信支付' - } - ]; + } + // #endif + + // 兜底:至少保留一个微信 + if (!methods.length) { + methods.push({ paymentMethodType: 'WECHAT', paymentMethodName: '微信支付' }) + } + + paymentMethods.value = methods + if (paymentMethods.value.length > 0) { + selectedPaymentMethod.value = paymentMethods.value[0].paymentMethodType } } @@ -315,8 +330,85 @@ title: t('common.processing') }) + const method = selectedPaymentMethod.value + + // 微信小程序支付押金 + // #ifdef MP-WEIXIN + if (method === 'WECHAT') { + const wxRes = await createWxPayment(orderInfo.value.orderNo) + if (wxRes.code === 200 && wxRes.data) { + const payData = wxRes.data + await new Promise((resolve, reject) => { + wx.requestPayment({ + ...payData, + success: resolve, + fail: reject + }) + }) + // 支付成功后轮询微信支付状态 + startPaymentStatusPolling('WECHAT') + return + } else { + throw new Error(wxRes.msg || t('payment.createPayOrderFailed')) + } + } + // #endif + + // 支付宝小程序支付押金 + // #ifdef MP-ALIPAY + if (method === 'ALIPAY') { + const aliRes = await createAliPayment(orderInfo.value.orderNo) + if (aliRes.code === 200 && aliRes.data) { + // 后端当前实际返回结构示例: + // { code:200, msg:'操作成功', data:{ tradeNo:'xxx', outTradeNo:'yyy' } } + const tradeNO = aliRes.data.tradeNo || aliRes.data.outTradeNo + const payForm = aliRes.data.payForm || aliRes.data.orderStr + + if (!tradeNO && !payForm) { + throw new Error('未获取到支付宝支付参数') + } + + // 优先使用 tradeNO 方式,其次兼容老的 orderStr 方式 + if (tradeNO) { + my.tradePay({ + tradeNO, + success: (res) => { + if (res.resultCode === '9000') { + startPaymentStatusPolling('ALIPAY') + } else { + uni.showToast({ title: t('payment.paymentFailed'), icon: 'none' }) + } + }, + fail: () => { + uni.showToast({ title: t('payment.paymentFailed'), icon: 'none' }) + } + }) + } else { + my.tradePay({ + orderStr: payForm, + success: (res) => { + if (res.resultCode === '9000') { + startPaymentStatusPolling('ALIPAY') + } else { + uni.showToast({ title: t('payment.paymentFailed'), icon: 'none' }) + } + }, + fail: () => { + uni.showToast({ title: t('payment.paymentFailed'), icon: 'none' }) + } + }) + } + return + } else { + throw new Error(aliRes.msg || t('payment.createPayOrderFailed')) + } + } + // #endif + + // H5 + Antom 聚合支付 + // #ifdef H5 const osType = getOsType(); - const res = await createAntomPayment(orderInfo.value.orderNo, selectedPaymentMethod.value, osType) + const res = await createAntomPayment(orderInfo.value.orderNo, method, osType) if (res && res.code === 200 && res.data) { const paymentUrl = res.data.h5Url; @@ -326,21 +418,16 @@ } uni.hideLoading(); - // #ifdef H5 uni.setStorageSync('pendingPaymentNo', orderId.value); - // 跳转到支付页面 - // uni.navigateTo({ - // url: `/pages/webview/index?url=${encodeURIComponent(paymentUrl)}&title=支付` - // }); window.open(paymentUrl); - // #endif - - // 开始轮询支付状态 - startPaymentStatusPolling(); + // 开始轮询支付状态(传入当前选中的支付方式类型) + startPaymentStatusPolling(method); + return } else { throw new Error(res?.msg || t('payment.createPayOrderFailed')) } + // #endif } catch (error) { console.error('支付失败:', error) uni.showToast({ @@ -352,14 +439,22 @@ } } - // 轮询支付状态 + // 轮询定时器 let pollingTimer = null; - const startPaymentStatusPolling = () => { + + /** + * 统一的支付状态轮询方法 + * @param {string} paymentMethodType - 支付方式类型,如 'WECHAT' | 'ALIPAY' | 'WECHATPAY' 等,与 selectedPaymentMethod 保持一致 + */ + const startPaymentStatusPolling = (paymentMethodType = null) => { // 清除之前的定时器 if (pollingTimer) { clearInterval(pollingTimer); } + // 如果没有传入支付方式类型,使用当前选中的支付方式 + const methodType = paymentMethodType || selectedPaymentMethod.value; + let pollCount = 0; const maxPollCount = 60; // 最多轮询60次(5分钟) @@ -376,32 +471,64 @@ } try { + let res; + let status, successStatus, failStatuses; + + // #ifdef H5 + // H5 环境统一使用 Antom 聚合支付 API const osType = getOsType(); - const res = await getAntomPaymentStatus(orderInfo.value.orderNo, osType); + res = await getAntomPaymentStatus(orderInfo.value.orderNo, osType); if (res && res.code === 200 && res.data) { - const paymentStatus = res.data.paymentStatus; + status = res.data.paymentStatus; + successStatus = 'SUCCESS'; + failStatuses = ['FAIL', 'CANCELLED']; + } + // #endif + + // #ifdef MP-WEIXIN + // 微信小程序:根据支付方式类型判断 + if (methodType === 'WECHAT' || methodType === 'WECHATPAY') { + res = await getWxPaymentStatus(orderInfo.value.orderNo); + if (res && res.code === 200 && res.data) { + status = res.data.tradeStatus; + successStatus = 'SUCCESS'; + failStatuses = ['FAIL', 'CANCELLED']; + } + } + // #endif + + // #ifdef MP-ALIPAY + // 支付宝小程序 + if (methodType === 'ALIPAY') { + res = await getAliPaymentStatus(orderInfo.value.orderNo); + if (res && res.code === 200 && res.data) { + status = res.data.tradeStatus; + successStatus = 'TRADE_SUCCESS'; + failStatuses = ['TRADE_FAIL', 'TRADE_CANCELLED']; + } + } + // #endif - if (paymentStatus === 'SUCCESS') { + // 处理支付状态结果 + if (res && res.code === 200 && res.data && status) { + // 支付成功 + if (status === successStatus) { clearInterval(pollingTimer); - // uni.showToast({ - // title: t('payment.paymentSuccess'), - // icon: 'success' - // }); - try { await updateUserBalance(orderId.value); } catch (error) { console.warn('更新用户余额失败:', error); } - console.log(orderInfo); setTimeout(() => { uni.redirectTo({ url: `/pages/order/success?orderId=${orderId.value}&deviceId=${orderInfo.value.deviceNo}` }); }, 1500); - } else if (paymentStatus === 'FAIL' || paymentStatus === 'CANCELLED') { + } + // 支付失败 + else if (failStatuses && failStatuses.includes(status)) { clearInterval(pollingTimer); uni.showToast({ title: '支付失败,请重新支付', @@ -410,11 +537,16 @@ } } } catch (error) { - console.error('查询支付状态失败:', error); + const errorMsg = methodType === 'ALIPAY' ? '支付宝' : (methodType === 'WECHAT' || methodType === 'WECHATPAY') ? '微信' : '支付'; + console.error(`查询${errorMsg}支付状态失败:`, error); } }, 5000); // 每5秒查询一次 } + // 兼容性方法:保持原有函数名,内部调用统一方法 + const startWxPaymentStatusPolling = () => startPaymentStatusPolling('WECHAT'); + const startAliPaymentStatusPolling = () => startPaymentStatusPolling('ALIPAY'); + // 更新导航栏倒计时 const updateNavBarCountdown = () => { const minutes = Math.floor(countdown.value / 60).toString().padStart(2, '0') diff --git a/subPackages/service/feedback/index.vue b/subPackages/service/feedback/index.vue index c7ede06..d37fe75 100644 --- a/subPackages/service/feedback/index.vue +++ b/subPackages/service/feedback/index.vue @@ -86,7 +86,7 @@ // 跳转到投诉记录列表 const navigateToRecord = () => { uni.navigateTo({ - url: '/pages/feedback/list' + url: '/subPackages/service/feedback/list' }) } diff --git a/subPackages/service/feedback/list.vue b/subPackages/service/feedback/list.vue index 49062c0..96e5f76 100644 --- a/subPackages/service/feedback/list.vue +++ b/subPackages/service/feedback/list.vue @@ -270,7 +270,7 @@ // 跳转到详情页 const navigateToDetail = (item) => { uni.navigateTo({ - url: `/pages/feedback/detail?id=${item.id || item.feedbackId}` + url: `/subPackages/service/feedback/detail?id=${item.id || item.feedbackId}` }); }; diff --git a/subPackages/service/help/index.vue b/subPackages/service/help/index.vue index ba308c6..91767d8 100644 --- a/subPackages/service/help/index.vue +++ b/subPackages/service/help/index.vue @@ -2,18 +2,27 @@ - - + + {{ $t(item.question) }} + + + {{ $t(item.answer) }} - - + + @@ -34,7 +43,7 @@