feat:我的订单+支付返回

cz_dev
wk 2026-03-04 16:58:40 +08:00
commit 346a17f8b2
5 changed files with 690 additions and 361 deletions

108
App.vue
View File

@ -1,4 +1,6 @@
<script> <script>
import { updateLuOrderPayStatus } from "@/api/service";
export default { export default {
globalData: { globalData: {
// //
@ -11,9 +13,66 @@
}, },
onShow: function() { onShow: function() {
console.log('App Show') console.log('App Show')
// 1. uni-app uni.getEnterOptionsSync() APIuni
const options = uni.getEnterOptionsSync();
console.log("查询到的返回数据")
console.log(options)
// 2. scene '1038'
if (options.scene === 1038 &&
options.referrerInfo?.appId === 'wxef277996acc166c3') {
//
const extraData = options.referrerInfo.extraData;
console.log("extraData",extraData)
if (!extraData) {
uni.showToast({
title: '当前通过物理按键返回,未接收到返参,建议自行查询交易结果',
icon: 'none',
duration: 3000
});
} else {
if (extraData.code === 'success') {
//
// 1. 使
const orderNumberFromExtra =
extraData.orderNumber || extraData.reqsn || extraData.orderNo;
// 2. 使
const storedOrderNumber = uni.getStorageSync("lastOrderNumber");
const orderNumber = orderNumberFromExtra || storedOrderNumber;
if (orderNumber) {
this.startOrderStatusPolling(orderNumber);
} else {
uni.showToast({
title: '支付返回缺少订单号,请稍后在服务记录中查看',
icon: 'none',
duration: 3000
});
}
} else if (extraData.code === 'cancel') {
uni.showToast({
title: '支付已取消',
icon: 'none'
});
} else {
uni.showToast({
title: `支付失败:${extraData.errmsg || '未知错误'}`,
icon: 'none',
duration: 3000
});
}
}
}
}, },
onHide: function() { onHide: function() {
console.log('App Hide') console.log('App Hide')
//
if (this._orderStatusTimer) {
clearInterval(this._orderStatusTimer);
this._orderStatusTimer = null;
}
}, },
methods: { methods: {
// //
@ -42,6 +101,55 @@
} }
}, 100) }, 100)
} }
},
//
startOrderStatusPolling(orderNumber) {
//
if (this._orderStatusTimer) {
clearInterval(this._orderStatusTimer);
this._orderStatusTimer = null;
}
let times = 0;
const maxTimes = 5; // 20 1
this._orderStatusTimer = setInterval(async () => {
times++;
try {
const res = await updateLuOrderPayStatus({ orderNumber });
//
if (res) {
clearInterval(this._orderStatusTimer);
this._orderStatusTimer = null;
//
uni.removeStorageSync("lastOrderNumber");
uni.showToast({
title: '支付成功',
icon: 'success'
});
// tab
uni.navigateTo({
url: '/pages/profileSub/serviceRecords?tab=pending_verification'
});
} else if (times >= maxTimes) {
clearInterval(this._orderStatusTimer);
this._orderStatusTimer = null;
uni.showToast({
title: '支付状态确认超时,请稍后在服务记录中查看',
icon: 'none',
duration: 3000
});
}
} catch (error) {
console.error('查询订单支付状态失败:', error);
if (times >= maxTimes) {
clearInterval(this._orderStatusTimer);
this._orderStatusTimer = null;
}
}
}, 3000);
} }
} }
} }

View File

@ -65,6 +65,22 @@ export function setMemberCollect(params = {}) {
data: params, data: params,
}) })
} }
// 获取支付的签名
export function getPaySign(params = {}){
return request({
url: '/app-api/member/labor-union-pay/sign',
method: 'GET',
data: params,
})
}
// 创建购买订单
export function appBuy (params = {}){
return request({
url: '/app-api/member/lu-order/buy',
method: 'POST',
data: params,
})
}
// 创建会员司机公会分享记录 // 创建会员司机公会分享记录
export function createMemberShare(params = {}) { export function createMemberShare(params = {}) {
@ -86,12 +102,80 @@ export function isNeedMap(params = {}) {
// 工会优惠券/商品下单并发起微信支付(需要后端返回小程序支付参数) // 工会优惠券/商品下单并发起微信支付(需要后端返回小程序支付参数)
// 约定:后端返回字段需包含 timeStamp、nonceStr、package、signType、paySign或等价字段 // 约定:后端返回字段需包含 timeStamp、nonceStr、package、signType、paySign或等价字段
export function createGuildCouponWxPay(params = {}) { // export function createGuildCouponWxPay(params = {}) {
// return request({
// // TODO: 如后端实际路径不同,请替换这里的 url
// url: '/app-api/member/labor-union-coupon/pay',
// method: 'POST',
// data: params,
// showLoading: true,
// })
// }
// 获取lu(司机公会简称) 订单信息
export function getLuOrder (id){
return request({ return request({
// TODO: 如后端实际路径不同,请替换这里的 url url: '/app-api/member/lu-order/get?id='+id,
url: '/app-api/member/labor-union-coupon/pay', method: 'GET',
method: 'POST',
data: params,
showLoading: true,
}) })
} }
/// 获取我的订单列表
export function getLuMyOrderPage (params = {}){
return request({
url: '/app-api/member/lu-order/myPage',
method: 'GET',
data: params
})
}
// 订单支付状态更新
export function updateLuOrderPayStatus(params = {}){
return request({
url: '/app-api/member/lu-order/getPayStatus',
method: 'GET',
data: params,
})
}
// 删除优惠卷购买 (暂时不用)
// export function delCouponPurchaseBuy(id){
// return request({
// url: '/app-api/member/labor-union-coupon-purchase/delete?id='+id,
// method: 'DELETE',
// })
// }
// // 取消优惠卷购买 (暂时不用)
// export function cancelCouponPurchaseBuy(id){
// return request({
// url: '/app-api/member/labor-union-coupon-purchase/cancel?id='+id,
// method: 'POST',
// })
// }
// 获得我的订单列表
export function getMyOrderPage(params = {}){
return request({
url: '/app-api/member/lu-order/myPage',
method: 'GET',
data: params
})
}
// 删除订单
export function deleteOrder(id){
return request({
url: '/app-api/member/lu-order/delete?id='+id,
method: 'DELETE',
})
}
// 取消订单(待支付状态)
export function cancelOrder(params = {}){
return request({
url: '/app-api/member/lu-order/cancel',
method: 'POST',
data: params,
})
}

View File

@ -1,6 +1,6 @@
{ {
"name" : "demo", "name" : "司机公会用户端",
"appid" : "wxa3c0e1381f643f59", "appid" : "__UNI__BD011FB",
"description" : "", "description" : "",
"versionName" : "1.0.0", "versionName" : "1.0.0",
"versionCode" : "100", "versionCode" : "100",
@ -52,12 +52,11 @@
"mp-weixin" : { "mp-weixin" : {
"appid" : "wxa3c0e1381f643f59", "appid" : "wxa3c0e1381f643f59",
"setting" : { "setting" : {
"urlCheck" : false "urlCheck" : false,
"minified" : true
}, },
"usingComponents" : true, "usingComponents" : true,
"requiredPrivateInfos" : [ "requiredPrivateInfos" : [ "getLocation" ],
"getLocation"
],
"permission" : { "permission" : {
"scope.userLocation" : { "scope.userLocation" : {
"desc" : "你的位置信息将用于小程序位置接口的效果展示" "desc" : "你的位置信息将用于小程序位置接口的效果展示"
@ -71,7 +70,8 @@
"usingComponents" : true "usingComponents" : true
}, },
"mp-toutiao" : { "mp-toutiao" : {
"usingComponents" : true "usingComponents" : true,
"appid" : ""
}, },
"uniStatistics" : { "uniStatistics" : {
"enable" : false "enable" : false

View File

@ -80,9 +80,7 @@
>-</view >-</view
> >
<text class="quantity-number">{{ item.quantity || 0 }}</text> <text class="quantity-number">{{ item.quantity || 0 }}</text>
<view <view class="quantity-btn plus" @click="increaseQuantity(index)"
class="quantity-btn plus"
@click="increaseQuantity(index)"
>+</view >+</view
> >
</view> </view>
@ -118,12 +116,17 @@
</template> </template>
<script> <script>
import { getGuildStoreDetail, getGuildCoupon, createGuildCouponWxPay } from "@/api/service"; import {
getGuildStoreDetail,
getGuildCoupon,
getPaySign,
appBuy
} from "@/api/service";
import NavHeader from "@/components/NavHeader/NavHeader.vue"; import NavHeader from "@/components/NavHeader/NavHeader.vue";
export default { export default {
components: { components: {
NavHeader NavHeader,
}, },
data() { data() {
return { return {
@ -154,7 +157,10 @@ export default {
}, },
// 访 // 访
memberLevelName() { memberLevelName() {
return (this.userInfo && this.userInfo.level && this.userInfo.level.name) || '普通会员'; return (
(this.userInfo && this.userInfo.level && this.userInfo.level.name) ||
"普通会员"
);
}, },
}, },
onLoad(options) { onLoad(options) {
@ -182,11 +188,16 @@ export default {
onShow() { onShow() {
// //
// //
const token = uni.getStorageSync('token'); const token = uni.getStorageSync("token");
const newUserInfo = uni.getStorageSync('userInfo') || {}; const newUserInfo = uni.getStorageSync("userInfo") || {};
// //
if (token && (!this.userInfo || !this.userInfo.id) && newUserInfo && newUserInfo.id) { if (
token &&
(!this.userInfo || !this.userInfo.id) &&
newUserInfo &&
newUserInfo.id
) {
this.userInfo = newUserInfo; this.userInfo = newUserInfo;
// ID // ID
if (this.shopId) { if (this.shopId) {
@ -260,7 +271,8 @@ export default {
item.selected = !item.selected; item.selected = !item.selected;
if (!item.selected) { if (!item.selected) {
item.quantity = 0; item.quantity = 0;
} else if (item.quantity === 0) { } else if (!item.quantity || item.quantity <= 0) {
// 0 1
item.quantity = 1; item.quantity = 1;
} }
}, },
@ -293,7 +305,7 @@ export default {
// 100 // 100
formatPrice(price) { formatPrice(price) {
if (!price && price !== 0) { if (!price && price !== 0) {
return '0.00'; return "0.00";
} }
// //
const yuan = price / 100; const yuan = price / 100;
@ -319,97 +331,104 @@ export default {
}); });
return; return;
} }
//
// couponId:num;couponId:num 2324:1;2325:2
const couponStr = selectedItems
.map((item) => `${item.id}:${item.quantity}`)
.join(";");
// #ifndef MP-WEIXIN // this.totalAmount ,
const trxamt = (this.totalAmount * 100).toFixed(0);
console.log("购买信息: " + couponStr);
console.log("金额:" + trxamt);
const res = await appBuy({
shopId: this.shopId,
couponData: couponStr,
payableAmount: trxamt,
});
console.log(res);
if (!res) {
uni.showToast({ uni.showToast({
title: "请在微信小程序内使用微信支付", title: "购买失败,请稍后重试",
icon: "none", icon: "none",
}); });
return; }
// #endif // res
this.handlePay(res);
},
//
async handlePay(order) {
//
// const reqsn =
// "mini" + Date.now() + "" + Math.floor(Math.random() * 10000);
if (this.paying) return; const couponArray = order.couponPurchaseRespVOS || [];
this.paying = true; const couponMap = new Map();
couponArray.forEach((item) => {
const key = item.couponId;
if (!key) return;
// Map
const currentList = couponMap.get(key) || [];
currentList.push(item);
// Map
couponMap.set(key, currentList);
});
let bodyStr = ''
couponMap.forEach((couponList, couponId) => {
console.log(`优惠券ID${couponId}`);
console.log(`优惠券列表:`, couponList);
bodyStr = bodyStr + couponList[0].couponName + 'x' + couponList.length + ';';
});
const randomstr = Math.floor(Math.random() * 10000000) + "";
// "1"
const trxamt =
order.payableAmount != null && order.payableAmount !== ""
? String(order.payableAmount)
: "1";
//
let params = {
appid: "00390105", // appid
body: bodyStr, //
cusid: "56479107531MPMN", //
notify_url:
"http://e989c692.natappfree.cc/admin-api/member/lu-order/tlNotice", //
orgid: "56479107392N35H",
paytype: "W06",
randomstr: randomstr,
orderNumber: order.orderNumber,
remark: "1:" + order.orderNumber + ":" + bodyStr, // 1 , , body
reqsn: order.orderNumber,
sign: "",
signtype: "RSA",
trxamt,
version: "12",
};
if (order.orderNumber) {
uni.setStorageSync("lastOrderNumber", order.orderNumber);
}
try { try {
// 1) code openid / const sign = await getPaySign(params);
const loginRes = await new Promise((resolve, reject) => { params["sign"] = sign;
uni.login({ uni.navigateToMiniProgram({
provider: "weixin", appId: "wxef277996acc166c3", // appid
success: resolve, extraData: params,
fail: reject, success(res) {
console.log("小程序跳转成功", res);
},
fail(err) {
console.error("小程序跳转失败", err);
uni.showToast({ title: "跳转失败,请稍后重试", icon: "none" });
},
}); });
}); } catch (e) {
console.error("获取支付签名失败:", e);
const loginCode = loginRes && loginRes.code; uni.showToast({ title: "支付准备失败,请稍后重试", icon: "none" });
if (!loginCode) {
throw new Error("获取微信登录 code 失败");
}
// 2) +
const payRes = await createGuildCouponWxPay({
shopId: this.shopId,
//
items: selectedItems.map((it) => ({
id: it.id,
quantity: it.quantity,
})),
loginCode,
//
amount: this.totalAmount.toFixed(2),
});
// 3)
const raw = (payRes && (payRes.payParams || payRes.payInfo || payRes)) || {};
const timeStamp = String(raw.timeStamp || raw.timestamp || raw.time_stamp || "");
const nonceStr = raw.nonceStr || raw.nonce_str || "";
const pkg = raw.package || raw.packageValue || raw.package_value || "";
const signType = raw.signType || raw.sign_type || "MD5";
const paySign = raw.paySign || raw.pay_sign || "";
if (!timeStamp || !nonceStr || !pkg || !paySign) {
console.error("支付参数缺失:", raw);
uni.showToast({
title: "支付参数异常,请联系管理员",
icon: "none",
});
return;
}
// 4)
await new Promise((resolve, reject) => {
uni.requestPayment({
provider: "wxpay",
timeStamp,
nonceStr,
package: pkg,
signType,
paySign,
success: resolve,
fail: reject,
});
});
uni.showToast({
title: "支付成功",
icon: "success",
});
// /
setTimeout(() => {
uni.navigateTo({
url: "/pages/profileSub/serviceRecords",
});
}, 600);
} catch (err) {
console.error("支付失败:", err);
const msg = (err && (err.errMsg || err.message)) || "支付失败/已取消";
uni.showToast({
title: msg.includes("cancel") ? "已取消支付" : "支付失败",
icon: "none",
});
} finally {
this.paying = false;
} }
}, },
}, },

View File

@ -24,7 +24,7 @@
:class="{ active: currentTab === 'completed' }" :class="{ active: currentTab === 'completed' }"
@click="switchTab('completed')" @click="switchTab('completed')"
> >
<text class="tab-text">完成</text> <text class="tab-text">退款</text>
</view> </view>
<view <view
class="tab-item" class="tab-item"
@ -60,39 +60,62 @@
class="record-item" class="record-item"
v-for="(item, index) in currentList" v-for="(item, index) in currentList"
:key="index" :key="index"
@click="handleRecordClick(item)"
> >
<!-- 头部门店 + 状态 -->
<view class="record-header"> <view class="record-header">
<view class="record-title-row"> <view class="record-shop-row">
<text class="record-title">{{ item.serviceName }}</text> <text class="shop-name">{{ item.shopName }}</text>
<view class="status-badge" :class="getStatusClass(item.status)"> <view class="status-badge" :class="getStatusClass(item.status)">
<text class="status-text">{{ getStatusText(item.status) }}</text> <text class="status-text">{{ getStatusText(item.status) }}</text>
</view> </view>
</view> </view>
<text class="record-time">{{ item.createTime }}</text> <text class="record-time">{{ formatTime(item.createTime) }}</text>
</view> </view>
<view class="record-content"> <!-- 中部类似商品卡片 -->
<view class="record-info-row"> <view class="record-body" @click="handleRecordClick(item)">
<text class="info-label">服务类型</text> <view
<text class="info-value">{{ item.serviceType }}</text> class="record-goods"
v-for="(goods, gIndex) in getGoodsList(item)"
:key="goods.id || goods.couponId || gIndex"
>
<image
class="goods-image"
:src="
goods.coverUrl ||
goods.couponCoverUrl ||
goods.picUrl ||
'/static/home/entry_icon.png'
"
mode="aspectFill"
></image>
<view class="goods-info">
<text class="goods-title">{{ goods.couponName || goods.name }}</text>
<!-- <text class="goods-subtitle">
订单号{{ item.orderNumber }}
</text> -->
<view class="goods-meta-row">
<text class="goods-price">¥{{ formatFen(goods.salePrice) }}</text>
<text
class="goods-count"
v-if="(goods.num || goods.count || goods.quantity || goods.qty) > 1"
>
×{{ goods.num || goods.count || goods.quantity || goods.qty }}
</text>
</view> </view>
<view class="record-info-row">
<text class="info-label">服务门店</text>
<text class="info-value">{{ item.storeName }}</text>
</view> </view>
<view class="record-info-row">
<text class="info-label">订单号</text>
<text class="info-value">{{ item.orderNo }}</text>
</view> </view>
<view class="record-info-row">
<text class="info-label">订单金额</text>
<text class="info-value price">¥{{ item.amount }}</text>
</view> </view>
<!-- 底部合计 + 操作按钮 -->
<view class="record-footer">
<view class="total-info">
<text class="total-label">实付款</text>
<text class="total-amount">¥{{ formatFen(item.payableAmount) }}</text>
</view> </view>
<!-- 操作按钮区域 --> <!-- 操作按钮区域 -->
<view class="record-actions" v-if="item.status === 'pending_payment'"> <view class="record-actions" v-if="item.status === 1">
<button <button
class="action-btn cancel-btn" class="action-btn cancel-btn"
@click.stop="handleCancel(item)" @click.stop="handleCancel(item)"
@ -103,19 +126,16 @@
立即支付 立即支付
</button> </button>
</view> </view>
<view <view class="record-actions" v-else-if="item.status === 2">
class="record-actions" <!-- <button
v-else-if="item.status === 'pending_verification'"
>
<button
class="action-btn detail-btn" class="action-btn detail-btn"
@click.stop="handleViewDetail(item)" @click.stop="handleViewDetail(item)"
> >
查看详情 去核销
</button> </button> -->
</view> </view>
<view class="record-actions" v-else-if="item.status === 'completed'"> <view class="record-actions" v-else-if="item.status === 3">
<button <!-- <button
class="action-btn detail-btn" class="action-btn detail-btn"
@click.stop="handleViewDetail(item)" @click.stop="handleViewDetail(item)"
> >
@ -126,17 +146,18 @@
@click.stop="handleReview(item)" @click.stop="handleReview(item)"
> >
评价 评价
</button> </button> -->
</view> </view>
<view class="record-actions" v-else-if="item.status === 'cancelled'"> <view class="record-actions" v-else-if="item.status === 4">
<button <button
class="action-btn detail-btn" class="action-btn detail-btn"
@click.stop="handleViewDetail(item)" @click.stop="handleViewDetail(item)"
> >
查看详情 删除
</button> </button>
</view> </view>
</view> </view>
</view>
<!-- 加载更多提示 --> <!-- 加载更多提示 -->
<view class="load-more" v-if="currentList.length > 0"> <view class="load-more" v-if="currentList.length > 0">
@ -150,10 +171,11 @@
<script> <script>
import NavHeader from "@/components/NavHeader/NavHeader.vue"; import NavHeader from "@/components/NavHeader/NavHeader.vue";
import { getLuMyOrderPage, cancelOrder, getPaySign } from "@/api/service";
export default { export default {
components: { components: {
NavHeader NavHeader,
}, },
data() { data() {
return { return {
@ -164,128 +186,64 @@ export default {
hasMore: true, hasMore: true,
pageNo: 1, pageNo: 1,
pageSize: 10, pageSize: 10,
// //
mockData: { recordsMap: {
// pending_payment: [ pending_payment: [],
// { pending_verification: [],
// id: 1, completed: [],
// orderNo: "ORD20250101001", cancelled: [],
// serviceName: "",
// serviceType: "",
// storeName: "XX",
// amount: "299.00",
// createTime: "2025-01-15 10:30:00",
// status: "pending_payment",
// },
// {
// id: 2,
// orderNo: "ORD20250101002",
// serviceName: "",
// serviceType: "",
// storeName: "XX",
// amount: "158.00",
// createTime: "2025-01-14 15:20:00",
// status: "pending_payment",
// },
// {
// id: 3,
// orderNo: "ORD20250101003",
// serviceName: "",
// serviceType: "",
// storeName: "XX",
// amount: "199.00",
// createTime: "2025-01-13 09:15:00",
// status: "pending_payment",
// },
// ],
// pending_verification: [
// {
// id: 4,
// orderNo: "ORD20250101004",
// serviceName: "",
// serviceType: "",
// storeName: "XX",
// amount: "299.00",
// createTime: "2025-01-10 14:30:00",
// status: "pending_verification",
// },
// {
// id: 5,
// orderNo: "ORD20250101005",
// serviceName: "",
// serviceType: "",
// storeName: "XX",
// amount: "158.00",
// createTime: "2025-01-09 11:20:00",
// status: "pending_verification",
// },
// ],
// completed: [
// {
// id: 6,
// orderNo: "ORD20250101006",
// serviceName: "",
// serviceType: "",
// storeName: "XX",
// amount: "299.00",
// createTime: "2025-01-05 16:30:00",
// status: "completed",
// },
// {
// id: 7,
// orderNo: "ORD20250101007",
// serviceName: "",
// serviceType: "",
// storeName: "XX",
// amount: "158.00",
// createTime: "2025-01-04 10:20:00",
// status: "completed",
// },
// {
// id: 8,
// orderNo: "ORD20250101008",
// serviceName: "",
// serviceType: "",
// storeName: "XX",
// amount: "199.00",
// createTime: "2025-01-03 08:15:00",
// status: "completed",
// },
// ],
// cancelled: [
// {
// id: 9,
// orderNo: "ORD20250101009",
// serviceName: "",
// serviceType: "",
// storeName: "XX",
// amount: "299.00",
// createTime: "2025-01-02 14:30:00",
// status: "cancelled",
// },
// {
// id: 10,
// orderNo: "ORD20250101010",
// serviceName: "",
// serviceType: "",
// storeName: "XX",
// amount: "158.00",
// createTime: "2025-01-01 11:20:00",
// status: "cancelled",
// },
// ],
}, },
}; };
}, },
computed: { computed: {
currentList() { currentList() {
return this.mockData[this.currentTab] || []; return this.recordsMap[this.currentTab] || [];
}, },
}, },
onLoad() { onLoad(options) {
// tab使 tab
if (options && options.tab) {
this.currentTab = options.tab;
}
this.loadData(); this.loadData();
}, },
methods: { methods: {
// couponPurchaseRespVOS
getGoodsList(order) {
const list = (order && order.couponPurchaseRespVOS) || [];
return Array.isArray(list) && list.length ? list : [order || {}];
},
//
formatFen(fen) {
const n = Number(fen);
if (!Number.isFinite(n)) return fen || "0.00";
return (n / 100).toFixed(2);
},
// /
formatTime(val) {
if (val == null || val === "") return "";
let ts = Number(val);
if (!Number.isFinite(ts)) return val;
if (String(ts).length <= 10) ts *= 1000;
const d = new Date(ts);
const y = d.getFullYear();
const m = String(d.getMonth() + 1).padStart(2, "0");
const day = String(d.getDate()).padStart(2, "0");
const h = String(d.getHours()).padStart(2, "0");
const min = String(d.getMinutes()).padStart(2, "0");
const s = String(d.getSeconds()).padStart(2, "0");
return `${y}-${m}-${day} ${h}:${min}:${s}`;
},
// tab status
getStatusValue() {
const map = {
pending_payment: 1, //
pending_verification: 2, //
completed: 3, //
cancelled: 4, //
};
return map[this.currentTab];
},
// Tab // Tab
switchTab(tab) { switchTab(tab) {
if (this.currentTab === tab) return; if (this.currentTab === tab) return;
@ -306,34 +264,60 @@ export default {
}, },
// //
getStatusText(status) { getStatusText(status) {
const statusMap = { return status === 1
pending_payment: "待支付", ? "待支付"
pending_verification: "待核销", : status === 2
completed: "已完成", ? "待核销"
cancelled: "已取消", : status === 3
}; ? "已完成"
return statusMap[status] || ""; : status === 4
? "已取消"
: "";
}, },
// //
getStatusClass(status) { getStatusClass(status) {
const classMap = { return status === 1
pending_payment: "status-pending", ? "status-pending"
pending_verification: "status-verification", : status === 2
completed: "status-completed", ? "status-verification"
cancelled: "status-cancelled", : status === 3
}; ? "status-completed"
return classMap[status] || ""; : status === 4
? "status-cancelled"
: "";
}, },
// //
loadData() { async loadData(append = false) {
if (this.loading) return;
this.loading = true; this.loading = true;
// const status = this.getStatusValue();
setTimeout(() => { try {
const res = await getLuMyOrderPage({
pageNo: this.pageNo,
pageSize: this.pageSize,
status,
});
const list = res.list || [];
const currentList = this.recordsMap[this.currentTab] || [];
this.recordsMap = {
...this.recordsMap,
[this.currentTab]: append ? currentList.concat(list) : list,
};
//
this.hasMore = list.length >= this.pageSize;
} catch (e) {
console.error("加载服务记录失败:", e);
uni.showToast({
title: "加载服务记录失败",
icon: "none",
});
} finally {
this.loading = false; this.loading = false;
this.refreshing = false; this.refreshing = false;
this.loadingMore = false; this.loadingMore = false;
// 使 }
}, 500);
}, },
// //
handleRefresh() { handleRefresh() {
@ -347,12 +331,7 @@ export default {
if (this.hasMore && !this.loadingMore && !this.loading) { if (this.hasMore && !this.loadingMore && !this.loading) {
this.loadingMore = true; this.loadingMore = true;
this.pageNo += 1; this.pageNo += 1;
// this.loadData(true);
setTimeout(() => {
this.loadingMore = false;
//
this.hasMore = false;
}, 500);
} }
}, },
// //
@ -365,35 +344,95 @@ export default {
uni.showModal({ uni.showModal({
title: "提示", title: "提示",
content: "确定要取消该订单吗?", content: "确定要取消该订单吗?",
success: (res) => { success: async (res) => {
if (res.confirm) { if (res.confirm) {
//
const res = await cancelOrder({
id: item.id,
});
if (res) {
uni.showToast({ uni.showToast({
title: "订单已取消", title: "订单已取消",
icon: "success", icon: "success",
}); });
// this.loadData();
//
const index = this.mockData.pending_payment.findIndex(
(i) => i.id === item.id
);
if (index > -1) {
this.mockData.pending_payment.splice(index, 1);
//
this.mockData.cancelled.unshift({
...item,
status: "cancelled",
});
} }
} }
}, },
}); });
}, },
// // handlePay
handlePay(item) { async handlePay(item) {
uni.showToast({ if (!item || !item.orderNumber) {
title: "该功能正在开发中", uni.showToast({ title: "订单信息异常", icon: "none" });
icon: "none", return;
}
const couponArray = item.couponPurchaseRespVOS || [];
const couponMap = new Map();
couponArray.forEach((goods) => {
const key = goods.couponId;
if (!key) return;
const currentList = couponMap.get(key) || [];
currentList.push(goods);
couponMap.set(key, currentList);
}); });
let bodyStr = "";
couponMap.forEach((couponList) => {
bodyStr =
bodyStr +
(couponList[0] && couponList[0].couponName
? couponList[0].couponName
: "商品") +
"x" +
couponList.length +
";";
});
const randomstr = Math.floor(Math.random() * 10000000) + "";
const trxamt =
item.payableAmount != null && item.payableAmount !== ""
? String(item.payableAmount)
: "1";
const params = {
appid: "00390105",
body: bodyStr,
cusid: "56479107531MPMN",
notify_url:
"http://e989c692.natappfree.cc/admin-api/member/lu-order/tlNotice",
orgid: "56479107392N35H",
paytype: "W06",
randomstr: randomstr,
orderNumber: item.orderNumber,
remark: "1:" + item.orderNumber + ":" + bodyStr,
reqsn: item.orderNumber,
sign: "",
signtype: "RSA",
trxamt,
version: "12",
};
if (item.orderNumber) {
uni.setStorageSync("lastOrderNumber", item.orderNumber);
}
try {
const sign = await getPaySign(params);
params["sign"] = sign;
uni.navigateToMiniProgram({
appId: "wxef277996acc166c3",
extraData: params,
success(res) {
console.log("小程序跳转成功", res);
},
fail(err) {
console.error("小程序跳转失败", err);
uni.showToast({ title: "跳转失败,请稍后重试", icon: "none" });
},
});
} catch (e) {
console.error("获取支付签名失败:", e);
uni.showToast({ title: "支付准备失败,请稍后重试", icon: "none" });
}
}, },
// //
handleViewDetail(item) { handleViewDetail(item) {
@ -514,25 +553,23 @@ export default {
background-color: #ffffff; background-color: #ffffff;
border-radius: 20rpx; border-radius: 20rpx;
margin-bottom: 20rpx; margin-bottom: 20rpx;
padding: 30rpx; padding: 24rpx 24rpx 20rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05); box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
.record-header { .record-header {
margin-bottom: 24rpx; margin-bottom: 16rpx;
padding-bottom: 20rpx;
border-bottom: 1rpx solid #f0f0f0;
.record-title-row { .record-shop-row {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
margin-bottom: 12rpx; margin-bottom: 8rpx;
.record-title { .shop-name {
flex: 1; flex: 1;
font-family: PingFang-SC, PingFang-SC; font-family: PingFang-SC, PingFang-SC;
font-weight: bold; font-weight: 600;
font-size: 30rpx; font-size: 28rpx;
color: #1a1819; color: #1a1819;
} }
@ -621,14 +658,98 @@ export default {
} }
} }
} }
.record-body {
background-color: #f8f9fb;
border-radius: 16rpx;
padding: 18rpx;
.record-goods {
display: flex;
align-items: center;
margin-bottom: 16rpx;
.goods-image {
width: 120rpx;
height: 120rpx;
border-radius: 12rpx;
margin-right: 16rpx;
flex-shrink: 0;
}
.goods-info {
flex: 1;
display: flex;
flex-direction: column;
gap: 8rpx;
.goods-title {
font-family: PingFang-SC, PingFang-SC;
font-weight: 500;
font-size: 26rpx;
color: #1a1819;
}
.goods-subtitle {
font-family: PingFang-SC, PingFang-SC;
font-weight: 400;
font-size: 22rpx;
color: #888888;
}
.goods-meta-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 4rpx;
.goods-price {
font-family: PingFang-SC, PingFang-SC;
font-weight: 600;
font-size: 28rpx;
color: #d51c3c;
}
.goods-count {
font-family: PingFang-SC, PingFang-SC;
font-weight: 400;
font-size: 22rpx;
color: #666666;
}
}
}
}
}
.record-footer {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 4rpx;
.total-info {
display: flex;
align-items: baseline;
.total-label {
font-family: PingFang-SC, PingFang-SC;
font-weight: 400;
font-size: 22rpx;
color: #666666;
}
.total-amount {
margin-left: 4rpx;
font-family: PingFang-SC, PingFang-SC;
font-weight: 600;
font-size: 30rpx;
color: #1a1819;
}
}
.record-actions { .record-actions {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: flex-end; gap: 16rpx;
gap: 20rpx;
padding-top: 20rpx;
border-top: 1rpx solid #f0f0f0;
button { button {
margin: 0; margin: 0;
@ -636,32 +757,29 @@ export default {
} }
.action-btn { .action-btn {
width: 131rpx; min-width: 150rpx;
height: 50rpx; height: 56rpx;
border-radius: 10rpx; padding: 0 20rpx;
font-family: PingFang-SC, PingFang-SC; font-family: PingFang-SC, PingFang-SC;
font-weight: 500; font-weight: 500;
font-size: 26rpx; font-size: 24rpx;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
box-sizing: border-box;
&.cancel-btn {
background-color: #f5f5f5;
color: #666666;
} }
&.pay-btn { .pay-btn {
background-color: #004294; background-color: #004294;
color: #ffffff; color: #ffffff;
} }
&.detail-btn { .detail-btn {
background-color: #f5f5f5; background-color: #f5f5f5;
color: #666666; color: #666666;
} }
&.review-btn { .review-btn {
background-color: #004294; background-color: #004294;
color: #ffffff; color: #ffffff;
} }