Files
qingcheng-xiaochengxu/pages/course/courseOrderList/courseOrderList.js
2025-08-16 22:14:42 +08:00

243 lines
7.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { baseUrl } from "../../../request";
const { notLogin } = require('../../../utils/util')
// pages/course/courseOrderList/courseOrderList.js
Page({
data: {
orderList: [], // 后端返回的订单列表
hasModalShown: false, // 本次停留页面只弹一次
isMaskVisible: false
},
// —— 内部状态(不放 data避免多余 setData
_timer: null,
_isActive: false, // 页面是否处于“可见/激活”状态
_justEnteredAt: 0, // 进入页面时刻(可按需使用)
onLoad() {
this._isActive = true;
this._justEnteredAt = Date.now();
this.fetchOrders();
},
onShow() {
this._isActive = true;
this.fetchOrders(); // 如不想重复拉取可注释
},
onHide() {
this._isActive = false;
this._clearTimer();
},
onUnload() {
this._isActive = false;
this._clearTimer();
},
onPullDownRefresh() {
this.fetchOrders(); // stopPullDownRefresh 在 complete 里
},
// ========= 工具函数 =========
_clearTimer() {
if (this._timer) {
clearInterval(this._timer);
this._timer = null;
}
},
_pad2(n) {
return String(n).padStart(2, '0');
},
_fmtCountDownStr(totalSec) {
const sec = Math.max(0, totalSec | 0);
const m = Math.floor(sec / 60);
const s = sec % 60;
return `${this._pad2(m)}${this._pad2(s)}`;
},
// ========= 拉单 =========
fetchOrders() {
wx.request({
url: baseUrl + '/courseOrder/query/list',
method: 'POST',
header: { Authorization: wx.getStorageSync('token') },
success: res => {
if (res.data.code === 1) {
const now = Date.now();
const list = (res.data.data || []).map(it => {
// 解析时间iOS 兼容 + NaN 兜底)
const ts = new Date(String(it.createTime).replace(/-/g, '/')).getTime();
const createMs = Number.isFinite(ts) ? ts : now;
// 统一按 15 分钟有效期(若后端返回 expireTime建议直接用
const ttlMs = 15 * 60 * 1000;
let diff = Math.floor((createMs + ttlMs - now) / 1000);
diff = Math.max(0, diff);
if (it.orderStatus === '待支付') {
it.countDown = diff;
it.countDownStr = this._fmtCountDownStr(diff);
it._expiredNotified = false; // 每单的本地防重复标记
// 初始化阶段如果已经超时diff=0静默转关闭不弹窗
if (diff === 0) {
it.orderStatus = '交易关闭';
it.countDownStr = '';
}
} else {
it.countDown = 0;
it.countDownStr = '';
}
return it;
});
// 渲染 + 启动定时器
this.setData({ orderList: list }, () => this._startTimer());
} else {
notLogin(res.data.message);
}
},
fail: () => {
wx.showToast({ title: '网络错误', icon: 'none' });
},
complete: () => {
wx.stopPullDownRefresh();
}
});
},
// ========= 定时器刷新 =========
_startTimer() {
this._clearTimer();
// 如果已经没有“待支付”的订单,就不启动定时器
const hasPending = this.data.orderList.some(o => o.orderStatus === '待支付' && o.countDown > 0);
if (!hasPending) return;
this._timer = setInterval(() => {
// 不在激活页时不做任何 UI 相关动作(同时兜底不弹窗)
if (!this._isActive) return;
let needRerender = false;
const updated = this.data.orderList.map(item => {
if (item.orderStatus === '待支付' && item.countDown > 0) {
const next = item.countDown - 1;
item.countDown = next;
item.countDownStr = this._fmtCountDownStr(next);
needRerender = true;
if (next <= 0) {
item.orderStatus = '交易关闭';
item.countDownStr = '';
// —— 仅在“当前页面可见”时弹一次,并且每单只弹一次;本页全局也只弹一次
if (this._isActive && !item._expiredNotified && !this.data.hasModalShown) {
item._expiredNotified = true;
wx.showModal({
title: '提示',
content: '订单超时未支付,已关闭',
showCancel: false
});
this.setData({ hasModalShown: true });
}
}
}
return item;
});
if (needRerender) {
this.setData({ orderList: updated }, () => {
// 如果已经没有可继续倒计时的订单,关掉定时器
const stillPending = this.data.orderList.some(o => o.orderStatus === '待支付' && o.countDown > 0);
if (!stillPending) this._clearTimer();
});
} else {
// 没有需要更新的也关掉
this._clearTimer();
}
}, 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 }, // 与后端约定:支付接口传 id若传 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' });
}
});
},
// ========= 跳转 & 取消 =========
gotoOrderDetail(e) {
const orderId = e.currentTarget.dataset.id;
wx.navigateTo({
url: `/pages/course/orderDetail/orderDetail?id=${orderId}`,
});
},
cancelOrder(e) {
const id = e.currentTarget.dataset.id;
wx.showModal({
title: '取消订单',
content: '是否要取消该订单?',
success: res => {
if (res.confirm) {
wx.request({
url: baseUrl + "/courseOrder/cancel",
method: 'POST',
header: { Authorization: wx.getStorageSync('token') },
data: { id }, // 如果后端需要 { orderId: id },改这里的键名即可
success: r => {
if (r.data && r.data.code !== 1) {
wx.showToast({ title: r.data.message || '取消失败', icon: 'none' });
}
this.fetchOrders();
},
fail: () => wx.showToast({ title: '网络错误', icon: 'none' })
});
}
}
});
}
});