473 lines
11 KiB
JavaScript
473 lines
11 KiB
JavaScript
// pages/shangjia-chongzhi/index.js
|
||
import request from '../../utils/request';
|
||
|
||
Page({
|
||
data: {
|
||
// 商家余额
|
||
sjyue: '0.00',
|
||
|
||
// 充值金额相关
|
||
quickAmounts: [50, 100, 300, 500, 1000, 2000],
|
||
selectedAmount: 50, // 默认选择第一个
|
||
customAmount: '',
|
||
inputFocus: false,
|
||
|
||
// 金额限制
|
||
minAmount: 1,
|
||
maxAmount: 10000,
|
||
|
||
// 支付状态
|
||
canPay: false,
|
||
isLoading: false,
|
||
loadingText: '',
|
||
|
||
// 支付状态提示
|
||
showStatus: false,
|
||
statusText: '',
|
||
statusSubtext: '',
|
||
showAction: false,
|
||
actionText: '',
|
||
|
||
// 订单ID
|
||
currentDingdanid: '',
|
||
|
||
// 轮询相关
|
||
pollingCount: 0,
|
||
maxPollingCount: 15
|
||
},
|
||
|
||
onLoad() {
|
||
this.initPage();
|
||
},
|
||
|
||
onShow() {
|
||
this.loadShangjiaBalance();
|
||
this.registerNotificationComponent();
|
||
},
|
||
registerNotificationComponent() {
|
||
const app = getApp();
|
||
const notificationComp = this.selectComponent('#global-notification');
|
||
|
||
if (notificationComp && notificationComp.showNotification) {
|
||
console.log('🏪 商城页面注册通知组件');
|
||
app.globalData.globalNotification = {
|
||
show: (data) => notificationComp.showNotification(data),
|
||
hide: () => notificationComp.hideNotification()
|
||
};
|
||
}
|
||
},
|
||
|
||
// 初始化页面
|
||
initPage() {
|
||
this.loadShangjiaBalance();
|
||
this.checkPayCondition();
|
||
},
|
||
|
||
// 从全局变量加载商家余额
|
||
loadShangjiaBalance() {
|
||
const app = getApp();
|
||
const globalData = app.globalData || {};
|
||
const shangjiaData = globalData.shangjia || {};
|
||
|
||
this.setData({
|
||
sjyue: shangjiaData.sjyue || '0.00'
|
||
});
|
||
},
|
||
|
||
// 选择快捷金额
|
||
selectAmount(e) {
|
||
const amount = parseInt(e.currentTarget.dataset.amount);
|
||
|
||
this.setData({
|
||
selectedAmount: amount,
|
||
customAmount: '',
|
||
inputFocus: false
|
||
}, () => {
|
||
this.checkPayCondition();
|
||
});
|
||
},
|
||
|
||
// 自定义金额输入
|
||
onCustomInput(e) {
|
||
const value = e.detail.value;
|
||
|
||
// 只允许输入数字和小数点
|
||
let cleanedValue = value.replace(/[^\d.]/g, '');
|
||
|
||
// 只允许一个小数点
|
||
const dotCount = cleanedValue.split('.').length - 1;
|
||
if (dotCount > 1) {
|
||
cleanedValue = cleanedValue.substring(0, cleanedValue.lastIndexOf('.'));
|
||
}
|
||
|
||
// 限制小数点后两位
|
||
if (cleanedValue.includes('.')) {
|
||
const parts = cleanedValue.split('.');
|
||
if (parts[1].length > 2) {
|
||
cleanedValue = parts[0] + '.' + parts[1].substring(0, 2);
|
||
}
|
||
}
|
||
|
||
this.setData({
|
||
customAmount: cleanedValue,
|
||
selectedAmount: null
|
||
}, () => {
|
||
this.checkPayCondition();
|
||
});
|
||
},
|
||
|
||
// 输入框聚焦
|
||
onInputFocus() {
|
||
this.setData({
|
||
inputFocus: true,
|
||
selectedAmount: null
|
||
});
|
||
},
|
||
|
||
// 输入框失焦
|
||
onInputBlur() {
|
||
this.setData({
|
||
inputFocus: false
|
||
}, () => {
|
||
this.checkPayCondition();
|
||
});
|
||
},
|
||
|
||
// 检查金额是否有效
|
||
checkAmountValid() {
|
||
const amount = this.getSelectedAmount();
|
||
|
||
if (!amount || amount === '') {
|
||
return false;
|
||
}
|
||
|
||
const numAmount = parseFloat(amount);
|
||
const min = this.data.minAmount;
|
||
const max = this.data.maxAmount;
|
||
|
||
if (numAmount < min || numAmount > max || isNaN(numAmount)) {
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
},
|
||
|
||
// 获取选中的金额
|
||
getSelectedAmount() {
|
||
if (this.data.selectedAmount !== null && this.data.selectedAmount !== undefined) {
|
||
return this.data.selectedAmount.toString();
|
||
} else if (this.data.customAmount) {
|
||
return this.data.customAmount;
|
||
}
|
||
return null;
|
||
},
|
||
|
||
// 检查支付条件
|
||
checkPayCondition() {
|
||
const validAmount = this.checkAmountValid();
|
||
|
||
this.setData({
|
||
canPay: validAmount
|
||
});
|
||
},
|
||
|
||
// ========== 支付逻辑 ==========
|
||
|
||
// 处理支付
|
||
handlePay() {
|
||
if (!this.data.canPay) {
|
||
wx.showToast({
|
||
title: '请选择有效金额',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
|
||
const amount = this.getSelectedAmount();
|
||
const numAmount = parseFloat(amount);
|
||
|
||
// 确认支付
|
||
wx.showModal({
|
||
title: '确认充值',
|
||
content: `是否充值 ¥${numAmount.toFixed(2)}?`,
|
||
success: (res) => {
|
||
if (res.confirm) {
|
||
this.startPayment(numAmount);
|
||
}
|
||
}
|
||
});
|
||
},
|
||
|
||
// 开始支付流程
|
||
async startPayment(amount) {
|
||
this.showLoading('发起支付中...');
|
||
|
||
try {
|
||
const res = await request({
|
||
url: '/shangpin/sjcz',
|
||
method: 'POST',
|
||
data: {
|
||
jine: amount // 关键字段:后端接口要求"jine"
|
||
}
|
||
});
|
||
|
||
if (res.data.code === 200) {
|
||
const payParams = res.data.payParams;
|
||
const dingdanid = res.data.dingdanid;
|
||
|
||
this.setData({
|
||
currentDingdanid: dingdanid,
|
||
pollingCount: 0
|
||
});
|
||
|
||
// 调起微信支付
|
||
await this.wechatPay(payParams);
|
||
} else {
|
||
this.hideLoading();
|
||
wx.showToast({
|
||
title: res.data.message || '支付发起失败',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
} catch (error) {
|
||
console.error('发起支付失败:', error);
|
||
this.hideLoading();
|
||
wx.showToast({
|
||
title: '网络错误,请重试',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
},
|
||
|
||
// 微信支付
|
||
async wechatPay(payParams) {
|
||
this.showLoading('调起支付中...');
|
||
|
||
return new Promise((resolve, reject) => {
|
||
if (!payParams || !payParams.timeStamp || !payParams.paySign) {
|
||
this.hideLoading();
|
||
wx.showToast({
|
||
title: '支付参数错误',
|
||
icon: 'none'
|
||
});
|
||
reject(new Error('支付参数错误'));
|
||
return;
|
||
}
|
||
|
||
wx.requestPayment({
|
||
timeStamp: payParams.timeStamp,
|
||
nonceStr: payParams.nonceStr,
|
||
package: payParams.package,
|
||
signType: payParams.signType || 'MD5',
|
||
paySign: payParams.paySign,
|
||
success: async () => {
|
||
this.hideLoading();
|
||
this.showStatusMessage('支付成功', '正在确认到账...', false);
|
||
|
||
try {
|
||
await this.startPolling();
|
||
resolve();
|
||
} catch (error) {
|
||
reject(error);
|
||
}
|
||
},
|
||
fail: async (res) => {
|
||
this.hideLoading();
|
||
|
||
let errorMsg = '支付失败';
|
||
if (res.errMsg.includes('cancel')) {
|
||
errorMsg = '您取消了支付';
|
||
}
|
||
|
||
this.showStatusMessage(errorMsg, '请重新尝试', true, '重新支付');
|
||
|
||
// 通知后端支付失败
|
||
try {
|
||
await this.notifyPaymentFailure();
|
||
} catch (error) {
|
||
console.error('支付失败通知失败:', error);
|
||
}
|
||
|
||
reject(new Error(res.errMsg));
|
||
}
|
||
});
|
||
});
|
||
},
|
||
|
||
// 开始轮询支付结果
|
||
async startPolling() {
|
||
this.setData({ pollingCount: 0 });
|
||
|
||
const poll = async () => {
|
||
if (this.data.pollingCount >= this.data.maxPollingCount) {
|
||
this.showStatusMessage('确认超时', '请联系客服确认到账情况', true, '联系客服');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
// 🟢 修改开始:修改checkPaymentStatus的调用和返回值处理
|
||
const result = await this.checkPaymentStatus();
|
||
|
||
if (result.success) {
|
||
// 🟢 修改:更新全局变量中的商家余额
|
||
const app = getApp();
|
||
if (app.globalData && app.globalData.shangjia) {
|
||
// 🟢 注意:后端返回yue,前端全局变量使用sjyue,保留两位小数
|
||
app.globalData.shangjia.sjyue = result.yue.toFixed(2);
|
||
console.log('🟢 全局变量商家余额已更新:', app.globalData.shangjia.sjyue);
|
||
}
|
||
|
||
this.showStatusMessage('充值成功', '余额已到账', true, '完成');
|
||
this.refreshBalance();
|
||
return;
|
||
}
|
||
// 🟢 修改结束
|
||
|
||
this.setData({
|
||
pollingCount: this.data.pollingCount + 1
|
||
});
|
||
|
||
const delay = this.calculatePollingDelay();
|
||
setTimeout(poll, delay);
|
||
} catch (error) {
|
||
console.error('轮询失败:', error);
|
||
this.setData({
|
||
pollingCount: this.data.pollingCount + 1
|
||
});
|
||
setTimeout(poll, 2000);
|
||
}
|
||
};
|
||
|
||
poll();
|
||
},
|
||
|
||
// 计算轮询延迟
|
||
calculatePollingDelay() {
|
||
const count = this.data.pollingCount;
|
||
if (count < 3) return 1000;
|
||
if (count < 6) return 2000;
|
||
if (count < 9) return 3000;
|
||
return 5000;
|
||
},
|
||
|
||
// 检查支付状态
|
||
async checkPaymentStatus() {
|
||
const dingdanid = this.data.currentDingdanid;
|
||
|
||
if (!dingdanid) {
|
||
throw new Error('订单ID缺失');
|
||
}
|
||
|
||
try {
|
||
const res = await request({
|
||
url: '/shangpin/sjcg',
|
||
method: 'POST',
|
||
data: {
|
||
dingdanid: dingdanid // 后端接口要求"dingdanid"
|
||
}
|
||
});
|
||
|
||
// 🟢 修改开始:返回对象,包含成功状态和余额
|
||
if (res.data.code === 200) {
|
||
return {
|
||
success: true,
|
||
yue: res.data.yue // 🟢 注意:后端返回字段是yue
|
||
};
|
||
} else {
|
||
return { success: false };
|
||
}
|
||
// 🟢 修改结束
|
||
} catch (error) {
|
||
console.error('检查支付状态失败:', error);
|
||
return { success: false };
|
||
}
|
||
},
|
||
|
||
// 通知支付失败
|
||
async notifyPaymentFailure() {
|
||
const dingdanid = this.data.currentDingdanid;
|
||
|
||
if (!dingdanid) return;
|
||
|
||
try {
|
||
await request({
|
||
url: '/shangpin/sjshibai',
|
||
method: 'POST',
|
||
data: {
|
||
dingdanid: dingdanid // 后端接口要求"dingdanid"
|
||
}
|
||
});
|
||
} catch (error) {
|
||
console.error('支付失败通知失败:', error);
|
||
}
|
||
},
|
||
|
||
// 刷新余额
|
||
async refreshBalance() {
|
||
try {
|
||
this.loadShangjiaBalance();
|
||
} catch (error) {
|
||
console.error('刷新余额失败:', error);
|
||
}
|
||
},
|
||
|
||
// ========== 状态提示 ==========
|
||
|
||
// 显示状态消息
|
||
showStatusMessage(title, desc, showAction = false, actionBtnText = '') {
|
||
this.setData({
|
||
showStatus: true,
|
||
statusText: title,
|
||
statusSubtext: desc,
|
||
showAction: showAction,
|
||
actionText: actionBtnText
|
||
});
|
||
},
|
||
|
||
// 处理状态按钮点击
|
||
handleStatusAction() {
|
||
const actionText = this.data.actionText;
|
||
|
||
if (actionText === '重新支付' || actionText === '重试') {
|
||
this.setData({ showStatus: false });
|
||
setTimeout(() => {
|
||
this.handlePay();
|
||
}, 300);
|
||
} else if (actionText === '联系客服') {
|
||
wx.showModal({
|
||
title: '联系客服',
|
||
content: '联系客服',
|
||
showCancel: false,
|
||
confirmText: '我知道了'
|
||
});
|
||
} else if (actionText === '完成') {
|
||
this.setData({ showStatus: false });
|
||
this.refreshBalance();
|
||
}
|
||
},
|
||
|
||
// ========== 工具方法 ==========
|
||
|
||
// 显示加载
|
||
showLoading(text = '加载中...') {
|
||
this.setData({
|
||
isLoading: true,
|
||
loadingText: text
|
||
});
|
||
},
|
||
|
||
// 隐藏加载
|
||
hideLoading() {
|
||
this.setData({
|
||
isLoading: false
|
||
});
|
||
},
|
||
|
||
// 页面卸载时清理
|
||
onUnload() {
|
||
this.setData({
|
||
showStatus: false,
|
||
isLoading: false
|
||
});
|
||
}
|
||
}); |