feat:我的订单+支付返回
commit
346a17f8b2
108
App.vue
108
App.vue
|
|
@ -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() 调用(和微信小程序API一致,只是前缀改为uni)
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -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,47 +658,128 @@ 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;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue