2025-07-20 18:22:59 +08:00
|
|
|
|
import { baseUrl, globalImgUrl } from "../../../request";
|
|
|
|
|
|
|
|
|
|
Page({
|
|
|
|
|
data: {
|
2025-08-16 22:14:42 +08:00
|
|
|
|
countdown: "",
|
2025-07-20 18:22:59 +08:00
|
|
|
|
orderId: 0,
|
2025-08-16 22:14:42 +08:00
|
|
|
|
orderObj: {}, // 订单详情对象
|
|
|
|
|
_secondsRemaining: 0, // 内部倒计时秒数
|
|
|
|
|
_hasShownTimeout: false, // 是否已弹过“超时未支付”弹窗(本次页面停留期内)
|
2025-07-20 18:22:59 +08:00
|
|
|
|
globalImgUrl,
|
2025-08-16 22:14:42 +08:00
|
|
|
|
isMaskVisible: false,
|
|
|
|
|
_isActive: false // 页面是否处于可见状态
|
2025-07-20 18:22:59 +08:00
|
|
|
|
},
|
|
|
|
|
|
2025-08-16 22:14:42 +08:00
|
|
|
|
// —— 非 data 状态,避免无谓 setData
|
|
|
|
|
_timer: null,
|
|
|
|
|
|
2025-07-20 18:22:59 +08:00
|
|
|
|
onLoad(options) {
|
2025-08-16 22:14:42 +08:00
|
|
|
|
this.setData({ orderId: options.id || 0 });
|
2025-07-20 18:22:59 +08:00
|
|
|
|
this.getOrderDetail();
|
|
|
|
|
},
|
2025-08-16 22:14:42 +08:00
|
|
|
|
|
|
|
|
|
onShow() {
|
|
|
|
|
this.setData({ _isActive: true });
|
2025-08-08 19:21:04 +08:00
|
|
|
|
},
|
2025-08-16 22:14:42 +08:00
|
|
|
|
|
|
|
|
|
onHide() {
|
|
|
|
|
this.setData({ _isActive: false });
|
|
|
|
|
this._clearTimer();
|
|
|
|
|
},
|
|
|
|
|
|
2025-07-20 18:22:59 +08:00
|
|
|
|
onUnload() {
|
2025-08-16 22:14:42 +08:00
|
|
|
|
this.setData({ _isActive: false });
|
|
|
|
|
this._clearTimer();
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
onPullDownRefresh() {
|
|
|
|
|
this.getOrderDetail(); // stopPullDownRefresh 放到 complete 里,更稳
|
2025-07-20 18:22:59 +08:00
|
|
|
|
},
|
|
|
|
|
|
2025-08-16 22:14:42 +08:00
|
|
|
|
// ====== 工具函数 ======
|
|
|
|
|
_clearTimer() {
|
|
|
|
|
if (this._timer) {
|
|
|
|
|
clearInterval(this._timer);
|
|
|
|
|
this._timer = null;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
_pad2(n) {
|
|
|
|
|
return String(n).padStart(2, "0");
|
|
|
|
|
},
|
|
|
|
|
_format(sec) {
|
|
|
|
|
const m = Math.floor(sec / 60);
|
|
|
|
|
const s = sec % 60;
|
|
|
|
|
return `${this._pad2(m)}分${this._pad2(s)}秒`;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// ====== 拉取订单详情并初始化倒计时 ======
|
2025-07-20 18:22:59 +08:00
|
|
|
|
getOrderDetail() {
|
|
|
|
|
wx.request({
|
2025-08-16 22:14:42 +08:00
|
|
|
|
url: baseUrl + "/courseOrder/query/detail",
|
|
|
|
|
method: "POST",
|
2025-07-20 18:22:59 +08:00
|
|
|
|
data: { id: this.data.orderId },
|
2025-08-16 22:14:42 +08:00
|
|
|
|
header: { Authorization: wx.getStorageSync("token") },
|
|
|
|
|
success: (res) => {
|
|
|
|
|
if (res.data.code !== 1) {
|
|
|
|
|
wx.showToast({ title: res.data.message || "获取失败", icon: "none" });
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const order = res.data.data || {};
|
2025-07-20 18:22:59 +08:00
|
|
|
|
this.setData({ orderObj: order });
|
|
|
|
|
|
2025-08-16 22:14:42 +08:00
|
|
|
|
// 只有“待支付”才需要倒计时;其它状态关掉计时器并清空文案
|
|
|
|
|
if (order.orderStatus === "待支付") {
|
2025-07-20 18:22:59 +08:00
|
|
|
|
this._initFromCreateTime(order.createTime);
|
2025-08-16 22:14:42 +08:00
|
|
|
|
} else {
|
|
|
|
|
this._clearTimer();
|
|
|
|
|
this.setData({ countdown: "" });
|
2025-07-20 18:22:59 +08:00
|
|
|
|
}
|
|
|
|
|
},
|
2025-08-16 22:14:42 +08:00
|
|
|
|
fail: () => wx.showToast({ title: "网络错误", icon: "none" }),
|
|
|
|
|
complete: () => wx.stopPullDownRefresh(),
|
2025-07-20 18:22:59 +08:00
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 计算剩余秒数并启动定时器
|
|
|
|
|
_initFromCreateTime(createTime) {
|
2025-08-16 22:14:42 +08:00
|
|
|
|
const ts = new Date(String(createTime).replace(/-/g, "/")).getTime();
|
|
|
|
|
const createMs = Number.isFinite(ts) ? ts : Date.now();
|
|
|
|
|
const ttlMs = 15 * 60 * 1000; // 15分钟有效
|
2025-07-20 18:22:59 +08:00
|
|
|
|
const now = Date.now();
|
2025-08-16 22:14:42 +08:00
|
|
|
|
let diff = Math.floor((createMs + ttlMs - now) / 1000);
|
|
|
|
|
diff = Math.max(0, diff);
|
2025-07-20 18:22:59 +08:00
|
|
|
|
|
2025-08-16 22:14:42 +08:00
|
|
|
|
// 初始化阶段:如果已过期,静默转“交易关闭”(不弹窗,避免干扰)
|
|
|
|
|
if (diff === 0) {
|
|
|
|
|
const o = { ...this.data.orderObj, orderStatus: "交易关闭" };
|
|
|
|
|
this._clearTimer();
|
|
|
|
|
this.setData({ orderObj: o, countdown: "" });
|
|
|
|
|
return;
|
2025-07-20 18:22:59 +08:00
|
|
|
|
}
|
2025-08-16 22:14:42 +08:00
|
|
|
|
|
|
|
|
|
// 未过期:初始化倒计时并启动
|
|
|
|
|
this._clearTimer();
|
|
|
|
|
this.setData({
|
|
|
|
|
_secondsRemaining: diff,
|
|
|
|
|
countdown: this._format(diff),
|
|
|
|
|
_hasShownTimeout: false, // 重置本页弹窗标记
|
|
|
|
|
});
|
|
|
|
|
this._startTimer();
|
2025-07-20 18:22:59 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 每秒递减
|
|
|
|
|
_startTimer() {
|
2025-08-16 22:14:42 +08:00
|
|
|
|
this._clearTimer();
|
2025-07-20 18:22:59 +08:00
|
|
|
|
this._timer = setInterval(() => {
|
2025-08-16 22:14:42 +08:00
|
|
|
|
const sec = this.data._secondsRemaining - 1;
|
|
|
|
|
|
2025-07-20 18:22:59 +08:00
|
|
|
|
if (sec <= 0) {
|
2025-08-16 22:14:42 +08:00
|
|
|
|
this._clearTimer();
|
|
|
|
|
this._handleTimeout(); // 到点且在当前页,才弹窗
|
|
|
|
|
return;
|
2025-07-20 18:22:59 +08:00
|
|
|
|
}
|
2025-08-16 22:14:42 +08:00
|
|
|
|
|
|
|
|
|
this.setData({
|
|
|
|
|
_secondsRemaining: sec,
|
|
|
|
|
countdown: this._format(sec),
|
|
|
|
|
});
|
2025-07-20 18:22:59 +08:00
|
|
|
|
}, 1000);
|
|
|
|
|
},
|
|
|
|
|
|
2025-08-16 22:14:42 +08:00
|
|
|
|
// 超时处理:仅在当前页可见时弹一次,并把状态改为“交易关闭”
|
2025-07-20 18:22:59 +08:00
|
|
|
|
_handleTimeout() {
|
2025-08-16 22:14:42 +08:00
|
|
|
|
const { _isActive, _hasShownTimeout } = this.data;
|
|
|
|
|
|
|
|
|
|
// 更新状态并隐藏倒计时
|
|
|
|
|
const o = { ...this.data.orderObj, orderStatus: "交易关闭" };
|
|
|
|
|
this.setData({ orderObj: o, countdown: "" });
|
|
|
|
|
|
|
|
|
|
// 只在当前页面 & 未弹过 时弹一次
|
|
|
|
|
if (_isActive && !_hasShownTimeout) {
|
2025-07-20 18:22:59 +08:00
|
|
|
|
wx.showModal({
|
2025-08-16 22:14:42 +08:00
|
|
|
|
title: "提示",
|
|
|
|
|
content: "订单超时未支付,已关闭",
|
|
|
|
|
showCancel: false,
|
|
|
|
|
complete: () => {
|
|
|
|
|
// 标记已弹
|
|
|
|
|
this.setData({ _hasShownTimeout: true });
|
|
|
|
|
},
|
2025-07-20 18:22:59 +08:00
|
|
|
|
});
|
2025-08-16 22:14:42 +08:00
|
|
|
|
} else {
|
2025-07-20 18:22:59 +08:00
|
|
|
|
this.setData({ _hasShownTimeout: true });
|
|
|
|
|
}
|
2025-08-16 22:14:42 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// ====== 支付相关 ======
|
|
|
|
|
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" });
|
|
|
|
|
},
|
2025-07-20 18:22:59 +08:00
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
2025-08-16 22:14:42 +08:00
|
|
|
|
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 }, // 若后端用 orderId,则把键名改为 orderId
|
|
|
|
|
success: (res) => {
|
|
|
|
|
wx.hideLoading();
|
|
|
|
|
if (res.data.code === 1) {
|
|
|
|
|
wx.redirectTo({
|
|
|
|
|
url: `/pages/course/orderDetail/orderDetail?id=${orderId}`,
|
|
|
|
|
complete: () => 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" });
|
|
|
|
|
},
|
|
|
|
|
});
|
2025-07-20 18:22:59 +08:00
|
|
|
|
},
|
|
|
|
|
|
2025-08-16 22:14:42 +08:00
|
|
|
|
// ====== 取消、退款(示例) ======
|
2025-07-20 18:22:59 +08:00
|
|
|
|
cancelOrder() {
|
|
|
|
|
wx.showModal({
|
2025-08-16 22:14:42 +08:00
|
|
|
|
title: "取消订单",
|
|
|
|
|
content: "是否要取消订单?",
|
|
|
|
|
success: (res) => {
|
2025-07-20 18:22:59 +08:00
|
|
|
|
if (res.confirm) {
|
|
|
|
|
wx.request({
|
|
|
|
|
url: baseUrl + "/courseOrder/cancel",
|
2025-08-16 22:14:42 +08:00
|
|
|
|
method: "POST",
|
|
|
|
|
header: { Authorization: wx.getStorageSync("token") },
|
|
|
|
|
data: { id: this.data.orderId }, // 后端如果需要 { orderId },改键名
|
|
|
|
|
success: (r) => {
|
|
|
|
|
if (!r.data || r.data.code !== 1) {
|
|
|
|
|
wx.showToast({ title: (r.data && r.data.message) || "取消失败", icon: "none" });
|
|
|
|
|
}
|
|
|
|
|
this.getOrderDetail();
|
|
|
|
|
},
|
|
|
|
|
fail: () => wx.showToast({ title: "网络错误", icon: "none" }),
|
2025-07-20 18:22:59 +08:00
|
|
|
|
});
|
|
|
|
|
}
|
2025-08-16 22:14:42 +08:00
|
|
|
|
},
|
2025-07-20 18:22:59 +08:00
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
goPay() {
|
2025-08-16 22:14:42 +08:00
|
|
|
|
wx.showToast({ title: "支付功能稍后开放", icon: "none" });
|
2025-07-20 18:22:59 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
refundOrder() {
|
2025-08-16 22:14:42 +08:00
|
|
|
|
wx.showToast({ title: "退款功能稍后开放", icon: "none" });
|
|
|
|
|
},
|
2025-07-20 18:22:59 +08:00
|
|
|
|
});
|