新增「我的订单」页面(订单中心)
- 微信审核要求交易类小程序提交订单中心 path,之前小程序没有订单页 - 新页面 pages/orders/orders:列表展示商品名 / 状态 / 订单号 / 金额 / 下单时间,接 GET /v1/orders - 我的页新增「我的订单」入口,文案走后台配置 profile.menu.orders - utils/api.js 补 getOrders(),utils/format.js 补 toDateTimeString()
This commit is contained in:
1 parent
014fa90dcd
commit
7d5db6a867
9 files changed
+172
-1
No files matched your search
@@ -10,6 +10,7 @@
|
|||||||
"pages/VideoDetailsPage/VideoDetailsPage",
|
"pages/VideoDetailsPage/VideoDetailsPage",
|
||||||
"pages/IndexNewCourseDetails/IndexNewCourseDetails",
|
"pages/IndexNewCourseDetails/IndexNewCourseDetails",
|
||||||
"pages/IndexFreeCourseDetails/IndexFreeCourseDetails",
|
"pages/IndexFreeCourseDetails/IndexFreeCourseDetails",
|
||||||
|
"pages/orders/orders",
|
||||||
"pages/ChangeUserInfo/ChangeUserInfo"
|
"pages/ChangeUserInfo/ChangeUserInfo"
|
||||||
],
|
],
|
||||||
"window": {
|
"window": {
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
// pages/orders/orders.js
|
||||||
|
//
|
||||||
|
// 订单中心:列出当前用户的全部订单,微信审核要求交易类小程序必须提供这个页面。
|
||||||
|
// 数据来自服务端 GET /v1/orders(只返回自己的单)。
|
||||||
|
const api = require('../../utils/api');
|
||||||
|
const format = require('../../utils/format');
|
||||||
|
const store = require('../../utils/store');
|
||||||
|
|
||||||
|
const app = getApp();
|
||||||
|
|
||||||
|
Page({
|
||||||
|
data: {
|
||||||
|
loading: true,
|
||||||
|
list: [],
|
||||||
|
/** 按钮文案走后台配置 */
|
||||||
|
contactText: '',
|
||||||
|
},
|
||||||
|
|
||||||
|
onLoad() {
|
||||||
|
// 等启动流程把配置和身份准备好再拉,避免首屏空白
|
||||||
|
app.ready().then(() => {
|
||||||
|
this.applyConfig();
|
||||||
|
this.load();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 每次回到页面都重新拉一次,付款回来能立刻看到新订单。 */
|
||||||
|
onShow() {
|
||||||
|
if (!this.data.loading) this.load();
|
||||||
|
},
|
||||||
|
|
||||||
|
applyConfig() {
|
||||||
|
this.setData({ contactText: store.cfg('course.button.contact') });
|
||||||
|
},
|
||||||
|
|
||||||
|
load() {
|
||||||
|
api
|
||||||
|
.getOrders()
|
||||||
|
.then((list) => {
|
||||||
|
this.setData({
|
||||||
|
loading: false,
|
||||||
|
list: (list || []).map((item) => ({
|
||||||
|
outTradeNo: item.outTradeNo,
|
||||||
|
title: item.courseTitle || '',
|
||||||
|
statusText: item.statusText || '',
|
||||||
|
status: item.status,
|
||||||
|
amountYuan: format.fenToYuan(item.amountFen),
|
||||||
|
createdAtText: format.toDateTimeString(item.createdAt),
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
this.setData({ loading: false });
|
||||||
|
wx.showToast({ title: (err && err.message) || '订单加载失败', icon: 'none' });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onShareAppMessage() {
|
||||||
|
return { title: store.cfg('share.title'), path: '/pages/index/index' };
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"navigationBarTitleText": "我的订单"
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<!--pages/orders/orders.wxml-->
|
||||||
|
<scroll-view class="order-page" scroll-y type="custom">
|
||||||
|
<view wx:if="{{loading}}" class="order-hint">加载中…</view>
|
||||||
|
<view wx:elif="{{list.length === 0}}" class="order-hint">暂无订单</view>
|
||||||
|
|
||||||
|
<block wx:else>
|
||||||
|
<view class="order-item" wx:for="{{list}}" wx:key="outTradeNo">
|
||||||
|
<view class="order-line">
|
||||||
|
<text class="order-title">{{item.title}}</text>
|
||||||
|
<text class="order-status">{{item.statusText}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="order-line order-sub">
|
||||||
|
<text>订单号 {{item.outTradeNo}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="order-line order-sub">
|
||||||
|
<text class="order-amount">¥{{item.amountYuan}}</text>
|
||||||
|
<text>{{item.createdAtText}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
|
||||||
|
<button class="order-service" open-type="contact">
|
||||||
|
<text>{{contactText}}</text>
|
||||||
|
</button>
|
||||||
|
</scroll-view>
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/* pages/orders/orders.wxss */
|
||||||
|
.order-page {
|
||||||
|
padding: 20rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-hint {
|
||||||
|
margin-top: 200rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-item {
|
||||||
|
width: 710rpx;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
padding: 24rpx;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
background-color: #fff;
|
||||||
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-line {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-title {
|
||||||
|
font-size: 30rpx;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-status {
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #00aa00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-sub {
|
||||||
|
margin-top: 12rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-amount {
|
||||||
|
color: #e60012;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-service {
|
||||||
|
width: 710rpx;
|
||||||
|
margin: 40rpx 0 60rpx;
|
||||||
|
border-radius: 45rpx;
|
||||||
|
font-size: 30rpx;
|
||||||
|
color: #fff;
|
||||||
|
background-color: #4caf50;
|
||||||
|
}
|
||||||
@@ -20,6 +20,8 @@ Page({
|
|||||||
text4: '',
|
text4: '',
|
||||||
text5: '',
|
text5: '',
|
||||||
text6: '',
|
text6: '',
|
||||||
|
/** 「我的订单」入口文案,走后台配置 */
|
||||||
|
ordersText: '',
|
||||||
},
|
},
|
||||||
|
|
||||||
onLoad() {
|
onLoad() {
|
||||||
@@ -43,6 +45,7 @@ Page({
|
|||||||
text4: store.cfg('profile.menu.contact'),
|
text4: store.cfg('profile.menu.contact'),
|
||||||
text5: store.cfg('profile.menu.wechat'),
|
text5: store.cfg('profile.menu.wechat'),
|
||||||
text6: store.cfg('profile.qrcode_caption'),
|
text6: store.cfg('profile.qrcode_caption'),
|
||||||
|
ordersText: store.cfg('profile.menu.orders'),
|
||||||
qrcodeUrl: qrcodeName ? config.STATIC_BASE_URL + '/Images/WXCode/' + qrcodeName + '.png' : '',
|
qrcodeUrl: qrcodeName ? config.STATIC_BASE_URL + '/Images/WXCode/' + qrcodeName + '.png' : '',
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -76,6 +79,11 @@ Page({
|
|||||||
wx.navigateTo({ url: '/pages/ChangeUserInfo/ChangeUserInfo' });
|
wx.navigateTo({ url: '/pages/ChangeUserInfo/ChangeUserInfo' });
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/** 订单中心:微信审核要求交易类小程序必须有,入口放在这一页。 */
|
||||||
|
toOrders() {
|
||||||
|
wx.navigateTo({ url: '/pages/orders/orders' });
|
||||||
|
},
|
||||||
|
|
||||||
showQrcode() {
|
showQrcode() {
|
||||||
this.setData({ showCode: true });
|
this.setData({ showCode: true });
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -31,6 +31,11 @@
|
|||||||
<text class="jiantou"> > </text>
|
<text class="jiantou"> > </text>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<button class="functions2" bind:tap="toOrders">
|
||||||
|
<text class="zuobianwenzi">{{ordersText}}</text>
|
||||||
|
<text class="jiantou"> > </text>
|
||||||
|
</button>
|
||||||
|
|
||||||
<button class="functions2" open-type="share">
|
<button class="functions2" open-type="share">
|
||||||
<text class="zuobianwenzi">{{text3}}</text>
|
<text class="zuobianwenzi">{{text3}}</text>
|
||||||
<text class="jiantou"> > </text>
|
<text class="jiantou"> > </text>
|
||||||
|
|||||||
@@ -218,6 +218,8 @@ const api = {
|
|||||||
getEntitlements: () => request({ url: '/v1/me/entitlements' }),
|
getEntitlements: () => request({ url: '/v1/me/entitlements' }),
|
||||||
|
|
||||||
// ── 订单与支付 ──────────────────────────────────────────────────────
|
// ── 订单与支付 ──────────────────────────────────────────────────────
|
||||||
|
/** 我的订单列表(订单中心用)。 */
|
||||||
|
getOrders: () => request({ url: '/v1/orders' }),
|
||||||
createOrder: (courseCode) =>
|
createOrder: (courseCode) =>
|
||||||
request({
|
request({
|
||||||
url: '/v1/orders',
|
url: '/v1/orders',
|
||||||
|
|||||||
@@ -12,6 +12,14 @@ function toDateString(value) {
|
|||||||
return d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate());
|
return d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** ISO 字符串 → YYYY-MM-DD HH:mm */
|
||||||
|
function toDateTimeString(value) {
|
||||||
|
if (!value) return '';
|
||||||
|
const d = new Date(value);
|
||||||
|
if (isNaN(d.getTime())) return '';
|
||||||
|
return toDateString(value) + ' ' + pad(d.getHours()) + ':' + pad(d.getMinutes());
|
||||||
|
}
|
||||||
|
|
||||||
/** 分 → 元(保留两位,去掉多余的 .00) */
|
/** 分 → 元(保留两位,去掉多余的 .00) */
|
||||||
function fenToYuan(fen) {
|
function fenToYuan(fen) {
|
||||||
const n = Number(fen);
|
const n = Number(fen);
|
||||||
@@ -20,5 +28,5 @@ function fenToYuan(fen) {
|
|||||||
return yuan % 1 === 0 ? String(yuan) : yuan.toFixed(2);
|
return yuan % 1 === 0 ? String(yuan) : yuan.toFixed(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { toDateString, fenToYuan };
|
module.exports = { toDateString, toDateTimeString, fenToYuan };
|
||||||
|
|
||||||
Reference in new issue
Block a user