模拟了微信支付功能

This commit is contained in:
2025-08-08 19:21:04 +08:00
parent 85df7bfc4e
commit c1817b6255
14 changed files with 246 additions and 30 deletions

View File

@ -5,6 +5,7 @@ Page({
data: { data: {
orderList: [], // 后端返回的订单列表 orderList: [], // 后端返回的订单列表
hasModalShown: false, // 弹框只显示一次 hasModalShown: false, // 弹框只显示一次
isMaskVisible: false
}, },
onLoad(options) { onLoad(options) {
@ -35,7 +36,7 @@ Page({
let list = res.data.data.map(item => { let list = res.data.data.map(item => {
// 计算从 createTime 到 now 剩余秒数 // 计算从 createTime 到 now 剩余秒数
const createMs = new Date(item.createTime.replace(/-/g,'/')).getTime(); const createMs = new Date(item.createTime.replace(/-/g,'/')).getTime();
let diff = Math.floor((createMs + 30*60*1000 - now) / 1000); let diff = Math.floor((createMs + 15*60*1000 - now) / 1000);
// 只有“待支付”才需要倒计时、过期置“交易取消” // 只有“待支付”才需要倒计时、过期置“交易取消”
if (item.orderStatus === '待支付') { if (item.orderStatus === '待支付') {
@ -80,6 +81,10 @@ Page({
// 每秒更新所有待支付订单的倒计时 // 每秒更新所有待支付订单的倒计时
startTimer() { startTimer() {
// ← 新增:如果已有定时器,先清掉它
if (this._timer) {
clearInterval(this._timer);
}
this._timer = setInterval(() => { this._timer = setInterval(() => {
const updated = this.data.orderList.map(item => { const updated = this.data.orderList.map(item => {
if (item.orderStatus === '待支付' && item.countDown > 0) { if (item.orderStatus === '待支付' && item.countDown > 0) {
@ -108,6 +113,62 @@ Page({
}, 1000); }, 1000);
}, },
showIsPayModal(e) {
const orderId = e.currentTarget.dataset.orderId;
wx.showModal({
title: '下单成功',
content: '您确定要支付吗?',
cancelText: '取消',
confirmText: '确定',
success: (res) => {
if (res.confirm) {
this.payOrder(orderId);
} else if (res.cancel) {
this.setData({ isMaskVisible: false });
}
},
fail: () => {
wx.hideLoading();
wx.showToast({
title: '网络错误,下单失败',
icon: 'none'
});
}
});
},
payOrder(orderId) {
// 同样先显示遮罩
this.setData({ isMaskVisible: true });
wx.showLoading({ title: '支付中...'});
wx.request({
url: baseUrl + '/courseOrder/payment',
method: 'POST',
header: { Authorization: wx.getStorageSync('token') },
data: { id: orderId},
success: res => {
wx.hideLoading();
if (res.data.code === 1) {
// 支付成功,跳转详情页
wx.redirectTo({
url: `/pages/course/orderDetail/orderDetail?id=${orderId}`,
success: res => {
// 先把遮罩关掉
this.setData({ isMaskVisible: false });
}
});
} else {
this.setData({ isMaskVisible: false });
wx.showToast({ title: res.data.message || '支付失败', icon: 'none' });
}
},
fail: () => {
wx.hideLoading();
this.setData({ isMaskVisible: false });
wx.showToast({ title: '网络错误,支付失败', icon: 'none' });
}
});
},
// 跳转订单详情 // 跳转订单详情
gotoOrderDetail(e) { gotoOrderDetail(e) {
const orderId = e.currentTarget.dataset.id; const orderId = e.currentTarget.dataset.id;
@ -135,11 +196,6 @@ Page({
} }
} }
}); });
}, }
// 支付订单
payOrder() {
// wx.navigateTo({ url: `/pages/pay/pay?orderId=${this.data.orderId}` });
wx.showToast({ title: '支付功能稍后开放', icon: 'none' });
},
}); });

View File

@ -30,11 +30,13 @@
<view wx:if="{{ item.orderStatus === '待支付' }}" class="flex-col justify-start items-center text-wrapper" catch:tap="cancelOrder" data-id="{{ item.id }}"> <view wx:if="{{ item.orderStatus === '待支付' }}" class="flex-col justify-start items-center text-wrapper" catch:tap="cancelOrder" data-id="{{ item.id }}">
<text class="font_7">取消订单</text> <text class="font_7">取消订单</text>
</view> </view>
<view wx:if="{{ item.orderStatus === '待支付' }}" class="flex-col justify-start items-center text-wrapper_2 ml-11" catch:tap="payOrder"> <view wx:if="{{ item.orderStatus === '待支付' }}" class="flex-col justify-start items-center text-wrapper_2 ml-11" catch:tap="showIsPayModal"
data-order-id="{{ item.id }}">
<text class="font_8">支付</text> <text class="font_8">支付</text>
</view> </view>
</view> </view>
</view> </view>
</view> </view>
</view> </view>
<view wx:if="{{isMaskVisible}}" class="page-mask"></view>
</view> </view>

View File

@ -9,6 +9,13 @@
.ml-11 { .ml-11 {
margin-left: 20.63rpx; margin-left: 20.63rpx;
} }
.page-mask {
position: fixed;
top: 0; left: 0;
width: 100%; height: 100%;
background-color: rgba(0, 0, 0, 0.3);
z-index: 9999;
}
.page { .page {
padding: 26.25rpx 0 50.63rpx; padding: 26.25rpx 0 50.63rpx;
background-color: #f8f8f8; background-color: #f8f8f8;

View File

@ -9,11 +9,15 @@ Page({
courseId: 0, // 课程id courseId: 0, // 课程id
courseObj: '', // 课程对象 courseObj: '', // 课程对象
globalImgUrl, // 全局图片 globalImgUrl, // 全局图片
isMaskVisible: false
}, },
// 创建订单方法 // 创建订单方法
createOrder() { createOrder() {
const { courseId } = this.data; const { courseId } = this.data;
// 1. 显示遮罩,阻止二次点击
this.setData({ isMaskVisible: true });
wx.showLoading({ title: '正在创建订单...' });
let orderId ; let orderId ;
wx.request({ wx.request({
url: baseUrl + '/courseOrder/add', url: baseUrl + '/courseOrder/add',
@ -25,16 +29,88 @@ Page({
Authorization :wx.getStorageSync('token'), Authorization :wx.getStorageSync('token'),
}, },
success : res => { success : res => {
console.log(res); orderId = res.data.data
this.setData({ this.setData({ orderId })
orderId: res.data.data wx.hideLoading();
}) if (res.data.code === 1) {
wx.navigateTo({ this.showIsPayModal(orderId)
url: `/pages/course/orderDetail/orderDetail?id=${this.data.orderId}`, } else {
}) // 下单失败,关闭遮罩
this.setData({ isMaskVisible: false });
wx.showModal({
title: '下单失败',
content: res.data.message || '下单失败',
showCancel: false,
confirmText: '知道了'
});
}
},
fail: () => {
wx.hideLoading();
this.setData({ isMaskVisible: false });
wx.showToast({ title: '网络错误,下单失败', icon: 'none' });
} }
}) })
},
showIsPayModal(orderId) {
wx.showModal({
title: '下单成功',
content: '您确定要支付吗?',
cancelText: '取消',
confirmText: '确定',
success: (res) => {
if (res.confirm) {
this.payOrder(orderId);
} else if (res.cancel) {
wx.navigateTo({
url: `/pages/course/orderDetail/orderDetail?id=${orderId}`,
success: res => {
// 先把遮罩关掉
this.setData({ isMaskVisible: false });
}
});
}
},
fail: () => {
wx.hideLoading();
wx.showToast({
title: '网络错误,下单失败',
icon: 'none'
});
}
});
},
payOrder(orderId) {
// 同样先显示遮罩
this.setData({ isMaskVisible: true });
wx.showLoading({ title: '支付中...'});
wx.request({
url: baseUrl + '/courseOrder/payment',
method: 'POST',
header: { Authorization: wx.getStorageSync('token') },
data: { id: orderId },
success: res => {
wx.hideLoading();
if (res.data.code === 1) {
// 支付成功,跳转详情页
wx.navigateTo({
url: `/pages/course/orderDetail/orderDetail?id=${orderId}`,
success: res => {
// 先把遮罩关掉
this.setData({ isMaskVisible: false });
}
});
} else {
this.setData({ isMaskVisible: false });
wx.showToast({ title: res.data.message || '支付失败', icon: 'none' });
}
},
fail: () => {
wx.hideLoading();
this.setData({ isMaskVisible: false });
wx.showToast({ title: '网络错误,支付失败', icon: 'none' });
}
});
}, },
// 获取课程详情 // 获取课程详情

View File

@ -38,9 +38,11 @@
<view class="footer"> <view class="footer">
<view class="flex-row justify-between items-center section_4"> <view class="flex-row justify-between items-center section_4">
<text class="font text_5">应付¥{{ courseObj.discountPrice }}</text> <text class="font text_5">应付¥{{ courseObj.discountPrice }}</text>
<view class="flex-col justify-center items-center text-wrapper" bind:tap="createOrder"> <view class="flex-col justify-center items-center text-wrapper" bindtap="createOrder">
<text class="font text_6">立即支付</text> <text class="font text_6">立即支付</text>
</view> </view>
</view> </view>
</view> </view>
<view wx:if="{{isMaskVisible}}" class="page-mask"></view>
</view> </view>

View File

@ -7,6 +7,14 @@
.ml-1 { .ml-1 {
margin-left: 1.88rpx; margin-left: 1.88rpx;
} }
/* app.wxss 或 当前页面 .wxss */
.page-mask {
position: fixed;
top: 0; left: 0;
width: 100%; height: 100%;
background-color: rgba(0, 0, 0, 0.3);
z-index: 9999;
}
.page { .page {
background-color: #f7f7f7; background-color: #f7f7f7;
width: 100%; width: 100%;

View File

@ -8,6 +8,7 @@ Page({
_secondsRemaining: 0, // 内部倒计时秒数 _secondsRemaining: 0, // 内部倒计时秒数
_hasShownTimeout: false, // 是否已弹过“超时未支付”弹窗 _hasShownTimeout: false, // 是否已弹过“超时未支付”弹窗
globalImgUrl, globalImgUrl,
isMaskVisible: false
}, },
onLoad(options) { onLoad(options) {
@ -15,7 +16,61 @@ Page({
this.setData({ orderId: options.id }); this.setData({ orderId: options.id });
this.getOrderDetail(); this.getOrderDetail();
}, },
showIsPayModal() {
const {orderId} = this.data
wx.showModal({
title: '下单成功',
content: '您确定要支付吗?',
cancelText: '取消',
confirmText: '确定',
success: (res) => {
if (res.confirm) {
this.payOrder(orderId);
} else if (res.cancel) {
this.setData({ isMaskVisible: false });
}
},
fail: () => {
wx.hideLoading();
wx.showToast({
title: '网络错误,下单失败',
icon: 'none'
});
}
});
},
payOrder(orderId) {
// 同样先显示遮罩
this.setData({ isMaskVisible: true });
wx.showLoading({ title: '支付中...'});
wx.request({
url: baseUrl + '/courseOrder/payment',
method: 'POST',
header: { Authorization: wx.getStorageSync('token') },
data: { id: orderId},
success: res => {
wx.hideLoading();
if (res.data.code === 1) {
// 支付成功,跳转详情页
wx.redirectTo({
url: `/pages/course/orderDetail/orderDetail?id=${orderId}`,
success: res => {
// 先把遮罩关掉
this.setData({ isMaskVisible: false });
}
});
} else {
this.setData({ isMaskVisible: false });
wx.showToast({ title: res.data.message || '支付失败', icon: 'none' });
}
},
fail: () => {
wx.hideLoading();
this.setData({ isMaskVisible: false });
wx.showToast({ title: '网络错误,支付失败', icon: 'none' });
}
});
},
onUnload() { onUnload() {
clearInterval(this._timer); clearInterval(this._timer);
}, },
@ -48,7 +103,7 @@ Page({
// 将 "2025-07-13 12:38:17" → 时间戳 // 将 "2025-07-13 12:38:17" → 时间戳
const createMs = new Date(createTime.replace(/-/g, '/')).getTime(); const createMs = new Date(createTime.replace(/-/g, '/')).getTime();
const now = Date.now(); const now = Date.now();
let diff = Math.floor((createMs + 30 * 60 * 1000 - now) / 1000); let diff = Math.floor((createMs + 15 * 60 * 1000 - now) / 1000);
if (diff <= 0) { if (diff <= 0) {
// 已超时 // 已超时

View File

@ -73,7 +73,7 @@
<view class="flex-col justify-start items-center text-wrapper" bindtap="cancelOrder"> <view class="flex-col justify-start items-center text-wrapper" bindtap="cancelOrder">
<text class="font_3 text_17">取消</text> <text class="font_3 text_17">取消</text>
</view> </view>
<view class="flex-col justify-start items-center text-wrapper_2" bindtap="goPay"> <view class="flex-col justify-start items-center text-wrapper_2" bindtap="showIsPayModal">
<text class="font_3 text_18">立即支付</text> <text class="font_3 text_18">立即支付</text>
</view> </view>
</view> </view>
@ -84,4 +84,5 @@
<text class="font_3 text_18">退款</text> <text class="font_3 text_18">退款</text>
</view> </view>
</view> </view>
<view wx:if="{{isMaskVisible}}" class="page-mask"></view>
</view> </view>

View File

@ -22,7 +22,14 @@
.mt-389 { .mt-389 {
margin-top: 729.38rpx; margin-top: 729.38rpx;
} }
/* app.wxss 或 当前页面 .wxss */
.page-mask {
position: fixed;
top: 0; left: 0;
width: 100%; height: 100%;
background-color: rgba(0, 0, 0, 0.3);
z-index: 9999;
}
/* 整体布局 */ /* 整体布局 */
.page { .page {
padding-top: 26.25rpx; padding-top: 26.25rpx;

View File

@ -1,5 +1,5 @@
// pages/personCenter/accountSetting/accountSetting.js // pages/personCenter/accountSetting/accountSetting.js
const { baseUrl } = require("../../../request"); const { baseUrl, globalImgUrl } = require("../../../request");
Page({ Page({
@ -9,7 +9,8 @@ Page({
data: { data: {
nickName: "", nickName: "",
userAvatar: "", userAvatar: "",
phoneNumber: "" phoneNumber: "",
globalImgUrl
}, },
gotoResetPwd() { gotoResetPwd() {
@ -66,7 +67,6 @@ Page({
if (res.data.code === 1) { if (res.data.code === 1) {
this.setData({ this.setData({
nickName: res.data.data.nickName, nickName: res.data.data.nickName,
// TODO 头像未连接
userAvatar: res.data.data.userAvatar, userAvatar: res.data.data.userAvatar,
phoneNumber: res.data.data.phoneNumber, phoneNumber: res.data.data.phoneNumber,
userAccount: res.data.data.userAccount userAccount: res.data.data.userAccount

View File

@ -3,7 +3,7 @@
<view class="flex-row self-stretch section"> <view class="flex-row self-stretch section">
<image <image
class="self-center image" class="self-center image"
src="./images/logo.png" src="{{globalImgUrl + userAvatar}}"
/> />
<view class="flex-col items-start flex-1 self-start group_2 ml-8"> <view class="flex-col items-start flex-1 self-start group_2 ml-8">
<text class="text">{{ nickName }}</text> <text class="text">{{ nickName }}</text>

View File

@ -20,6 +20,7 @@
.image { .image {
width: 121.88rpx; width: 121.88rpx;
height: 121.88rpx; height: 121.88rpx;
border-radius: 30rpx;
} }
.group_2 { .group_2 {
margin-top: 21.84rpx; margin-top: 21.84rpx;

View File

@ -274,8 +274,8 @@
</view> </view>
</view> </view>
<view class="flex-col list"> <view class="flex-col list">
<view class="flex-row justify-between items-center section_4" wx:if="{{isShowOrder}}"> <view class="flex-row justify-between items-center section_4" wx:if="{{isShowOrder}}" bindtap="courseOrder">
<view class="flex-row items-center" bindtap="courseOrder"> <view class="flex-row items-center">
<image <image
class="shrink-0 image_6" class="shrink-0 image_6"
src="./images/zhanghaoshezhi.png" src="./images/zhanghaoshezhi.png"

View File

@ -24,9 +24,10 @@
border-radius: 8.33rpx; border-radius: 8.33rpx;
} }
.image { .image {
padding: 10rpx; margin: 20rpx;
width: 151.25rpx; width: 141.25rpx;
height: 151.25rpx; height: 141.25rpx;
border-radius: 30rpx;
} }
button { button {
/* 去掉默认最小宽度 */ /* 去掉默认最小宽度 */