feat:我的订单+支付返回
commit
346a17f8b2
114
App.vue
114
App.vue
|
|
@ -1,4 +1,6 @@
|
|||
<script>
|
||||
import { updateLuOrderPayStatus } from "@/api/service";
|
||||
|
||||
export default {
|
||||
globalData: {
|
||||
// 用于从首页跳转到服务页面时传递需要高亮的分类
|
||||
|
|
@ -11,15 +13,72 @@
|
|||
},
|
||||
onShow: function() {
|
||||
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() {
|
||||
console.log('App Hide')
|
||||
// 页面整体隐藏时,清理轮询定时器
|
||||
if (this._orderStatusTimer) {
|
||||
clearInterval(this._orderStatusTimer);
|
||||
this._orderStatusTimer = null;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 检查登录状态
|
||||
checkLoginStatus() {
|
||||
const token = uni.getStorageSync('token')
|
||||
|
||||
|
||||
// 如果有token,且当前在登录页,则跳转到首页
|
||||
if (token) {
|
||||
// 延迟一下,确保页面已经初始化
|
||||
|
|
@ -27,7 +86,7 @@
|
|||
const pages = getCurrentPages()
|
||||
const currentPage = pages[pages.length - 1]
|
||||
const currentRoute = currentPage ? currentPage.route : ''
|
||||
|
||||
|
||||
// 如果当前在登录页,跳转到首页
|
||||
if (currentRoute === 'pages/login/login') {
|
||||
uni.switchTab({
|
||||
|
|
@ -42,6 +101,55 @@
|
|||
}
|
||||
}, 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -49,4 +157,4 @@
|
|||
|
||||
<style>
|
||||
/*每个页面公共css */
|
||||
</style>
|
||||
</style>
|
||||
|
|
@ -65,6 +65,22 @@ export function setMemberCollect(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 = {}) {
|
||||
|
|
@ -86,12 +102,80 @@ export function isNeedMap(params = {}) {
|
|||
|
||||
// 工会优惠券/商品下单并发起微信支付(需要后端返回小程序支付参数)
|
||||
// 约定:后端返回字段需包含 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({
|
||||
// TODO: 如后端实际路径不同,请替换这里的 url
|
||||
url: '/app-api/member/labor-union-coupon/pay',
|
||||
url: '/app-api/member/lu-order/get?id='+id,
|
||||
method: 'GET',
|
||||
})
|
||||
}
|
||||
/// 获取我的订单列表
|
||||
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,
|
||||
showLoading: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name" : "demo",
|
||||
"appid" : "wxa3c0e1381f643f59",
|
||||
"name" : "司机公会用户端",
|
||||
"appid" : "__UNI__BD011FB",
|
||||
"description" : "",
|
||||
"versionName" : "1.0.0",
|
||||
"versionCode" : "100",
|
||||
|
|
@ -52,12 +52,11 @@
|
|||
"mp-weixin" : {
|
||||
"appid" : "wxa3c0e1381f643f59",
|
||||
"setting" : {
|
||||
"urlCheck" : false
|
||||
"urlCheck" : false,
|
||||
"minified" : true
|
||||
},
|
||||
"usingComponents" : true,
|
||||
"requiredPrivateInfos" : [
|
||||
"getLocation"
|
||||
],
|
||||
"requiredPrivateInfos" : [ "getLocation" ],
|
||||
"permission" : {
|
||||
"scope.userLocation" : {
|
||||
"desc" : "你的位置信息将用于小程序位置接口的效果展示"
|
||||
|
|
@ -71,7 +70,8 @@
|
|||
"usingComponents" : true
|
||||
},
|
||||
"mp-toutiao" : {
|
||||
"usingComponents" : true
|
||||
"usingComponents" : true,
|
||||
"appid" : ""
|
||||
},
|
||||
"uniStatistics" : {
|
||||
"enable" : false
|
||||
|
|
|
|||
|
|
@ -80,9 +80,7 @@
|
|||
>-</view
|
||||
>
|
||||
<text class="quantity-number">{{ item.quantity || 0 }}</text>
|
||||
<view
|
||||
class="quantity-btn plus"
|
||||
@click="increaseQuantity(index)"
|
||||
<view class="quantity-btn plus" @click="increaseQuantity(index)"
|
||||
>+</view
|
||||
>
|
||||
</view>
|
||||
|
|
@ -118,12 +116,17 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { getGuildStoreDetail, getGuildCoupon, createGuildCouponWxPay } from "@/api/service";
|
||||
import {
|
||||
getGuildStoreDetail,
|
||||
getGuildCoupon,
|
||||
getPaySign,
|
||||
appBuy
|
||||
} from "@/api/service";
|
||||
import NavHeader from "@/components/NavHeader/NavHeader.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
NavHeader
|
||||
NavHeader,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -154,7 +157,10 @@ export default {
|
|||
},
|
||||
// 获取会员等级名称(安全访问)
|
||||
memberLevelName() {
|
||||
return (this.userInfo && this.userInfo.level && this.userInfo.level.name) || '普通会员';
|
||||
return (
|
||||
(this.userInfo && this.userInfo.level && this.userInfo.level.name) ||
|
||||
"普通会员"
|
||||
);
|
||||
},
|
||||
},
|
||||
onLoad(options) {
|
||||
|
|
@ -182,11 +188,16 @@ export default {
|
|||
onShow() {
|
||||
// 页面显示时,检查登录状态并更新用户信息
|
||||
// 如果之前未登录,现在已登录,重新加载数据
|
||||
const token = uni.getStorageSync('token');
|
||||
const newUserInfo = uni.getStorageSync('userInfo') || {};
|
||||
|
||||
const token = uni.getStorageSync("token");
|
||||
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;
|
||||
// 如果有店铺ID,重新加载店铺数据(特别是菜单数据,可能需要登录才能查看)
|
||||
if (this.shopId) {
|
||||
|
|
@ -260,7 +271,8 @@ export default {
|
|||
item.selected = !item.selected;
|
||||
if (!item.selected) {
|
||||
item.quantity = 0;
|
||||
} else if (item.quantity === 0) {
|
||||
} else if (!item.quantity || item.quantity <= 0) {
|
||||
// 选中时,如果当前数量为 0 或未设置,则默认数量为 1
|
||||
item.quantity = 1;
|
||||
}
|
||||
},
|
||||
|
|
@ -293,7 +305,7 @@ export default {
|
|||
// 格式化价格:将分转换为元(除以100,保留两位小数)
|
||||
formatPrice(price) {
|
||||
if (!price && price !== 0) {
|
||||
return '0.00';
|
||||
return "0.00";
|
||||
}
|
||||
// 将分转换为元
|
||||
const yuan = price / 100;
|
||||
|
|
@ -319,97 +331,104 @@ export default {
|
|||
});
|
||||
return;
|
||||
}
|
||||
//
|
||||
// 把选中的数据拼接成这样的数据 couponId:num;couponId:num 例如 2324:1;2325:2
|
||||
const couponStr = selectedItems
|
||||
.map((item) => `${item.id}:${item.quantity}`)
|
||||
.join(";");
|
||||
|
||||
// #ifndef MP-WEIXIN
|
||||
uni.showToast({
|
||||
title: "请在微信小程序内使用微信支付",
|
||||
icon: "none",
|
||||
// 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,
|
||||
});
|
||||
return;
|
||||
// #endif
|
||||
|
||||
if (this.paying) return;
|
||||
this.paying = true;
|
||||
|
||||
try {
|
||||
// 1) 获取小程序登录 code(用于后端换取 openid / 下单)
|
||||
const loginRes = await new Promise((resolve, reject) => {
|
||||
uni.login({
|
||||
provider: "weixin",
|
||||
success: resolve,
|
||||
fail: reject,
|
||||
});
|
||||
});
|
||||
|
||||
const loginCode = loginRes && loginRes.code;
|
||||
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,
|
||||
});
|
||||
});
|
||||
|
||||
console.log(res);
|
||||
if (!res) {
|
||||
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") ? "已取消支付" : "支付失败",
|
||||
title: "购买失败,请稍后重试",
|
||||
icon: "none",
|
||||
});
|
||||
} finally {
|
||||
this.paying = false;
|
||||
}
|
||||
// 调用支付信息 res 为订单信息
|
||||
this.handlePay(res);
|
||||
},
|
||||
// 支付调用
|
||||
async handlePay(order) {
|
||||
// 测试支付进行
|
||||
// const reqsn =
|
||||
// "mini" + Date.now() + "" + Math.floor(Math.random() * 10000);
|
||||
|
||||
const couponArray = order.couponPurchaseRespVOS || [];
|
||||
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 {
|
||||
const sign = await getPaySign(params);
|
||||
params["sign"] = sign;
|
||||
uni.navigateToMiniProgram({
|
||||
appId: "wxef277996acc166c3", // 目标小程序appid
|
||||
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" });
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
:class="{ active: currentTab === 'completed' }"
|
||||
@click="switchTab('completed')"
|
||||
>
|
||||
<text class="tab-text">已完成</text>
|
||||
<text class="tab-text">已退款</text>
|
||||
</view>
|
||||
<view
|
||||
class="tab-item"
|
||||
|
|
@ -60,62 +60,82 @@
|
|||
class="record-item"
|
||||
v-for="(item, index) in currentList"
|
||||
:key="index"
|
||||
@click="handleRecordClick(item)"
|
||||
>
|
||||
<!-- 头部:门店 + 状态 -->
|
||||
<view class="record-header">
|
||||
<view class="record-title-row">
|
||||
<text class="record-title">{{ item.serviceName }}</text>
|
||||
<view class="record-shop-row">
|
||||
<text class="shop-name">{{ item.shopName }}</text>
|
||||
<view class="status-badge" :class="getStatusClass(item.status)">
|
||||
<text class="status-text">{{ getStatusText(item.status) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<text class="record-time">{{ item.createTime }}</text>
|
||||
<text class="record-time">{{ formatTime(item.createTime) }}</text>
|
||||
</view>
|
||||
|
||||
<view class="record-content">
|
||||
<view class="record-info-row">
|
||||
<text class="info-label">服务类型:</text>
|
||||
<text class="info-value">{{ item.serviceType }}</text>
|
||||
</view>
|
||||
<view class="record-info-row">
|
||||
<text class="info-label">服务门店:</text>
|
||||
<text class="info-value">{{ item.storeName }}</text>
|
||||
</view>
|
||||
<view class="record-info-row">
|
||||
<text class="info-label">订单号:</text>
|
||||
<text class="info-value">{{ item.orderNo }}</text>
|
||||
</view>
|
||||
<view class="record-info-row">
|
||||
<text class="info-label">订单金额:</text>
|
||||
<text class="info-value price">¥{{ item.amount }}</text>
|
||||
<!-- 中部:类似商品卡片 -->
|
||||
<view class="record-body" @click="handleRecordClick(item)">
|
||||
<view
|
||||
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>
|
||||
</view>
|
||||
|
||||
<!-- 操作按钮区域 -->
|
||||
<view class="record-actions" v-if="item.status === 'pending_payment'">
|
||||
<button
|
||||
class="action-btn cancel-btn"
|
||||
@click.stop="handleCancel(item)"
|
||||
>
|
||||
取消订单
|
||||
</button>
|
||||
<button class="action-btn pay-btn" @click.stop="handlePay(item)">
|
||||
立即支付
|
||||
</button>
|
||||
</view>
|
||||
<view
|
||||
class="record-actions"
|
||||
v-else-if="item.status === 'pending_verification'"
|
||||
>
|
||||
<button
|
||||
class="action-btn detail-btn"
|
||||
@click.stop="handleViewDetail(item)"
|
||||
>
|
||||
查看详情
|
||||
</button>
|
||||
</view>
|
||||
<view class="record-actions" v-else-if="item.status === 'completed'">
|
||||
<button
|
||||
<!-- 底部:合计 + 操作按钮 -->
|
||||
<view class="record-footer">
|
||||
<view class="total-info">
|
||||
<text class="total-label">实付款:</text>
|
||||
<text class="total-amount">¥{{ formatFen(item.payableAmount) }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 操作按钮区域 -->
|
||||
<view class="record-actions" v-if="item.status === 1">
|
||||
<button
|
||||
class="action-btn cancel-btn"
|
||||
@click.stop="handleCancel(item)"
|
||||
>
|
||||
取消订单
|
||||
</button>
|
||||
<button class="action-btn pay-btn" @click.stop="handlePay(item)">
|
||||
立即支付
|
||||
</button>
|
||||
</view>
|
||||
<view class="record-actions" v-else-if="item.status === 2">
|
||||
<!-- <button
|
||||
class="action-btn detail-btn"
|
||||
@click.stop="handleViewDetail(item)"
|
||||
>
|
||||
去核销
|
||||
</button> -->
|
||||
</view>
|
||||
<view class="record-actions" v-else-if="item.status === 3">
|
||||
<!-- <button
|
||||
class="action-btn detail-btn"
|
||||
@click.stop="handleViewDetail(item)"
|
||||
>
|
||||
|
|
@ -126,15 +146,16 @@
|
|||
@click.stop="handleReview(item)"
|
||||
>
|
||||
评价
|
||||
</button>
|
||||
</view>
|
||||
<view class="record-actions" v-else-if="item.status === 'cancelled'">
|
||||
<button
|
||||
class="action-btn detail-btn"
|
||||
@click.stop="handleViewDetail(item)"
|
||||
>
|
||||
查看详情
|
||||
</button>
|
||||
</button> -->
|
||||
</view>
|
||||
<view class="record-actions" v-else-if="item.status === 4">
|
||||
<button
|
||||
class="action-btn detail-btn"
|
||||
@click.stop="handleViewDetail(item)"
|
||||
>
|
||||
删除
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
|
@ -150,10 +171,11 @@
|
|||
|
||||
<script>
|
||||
import NavHeader from "@/components/NavHeader/NavHeader.vue";
|
||||
import { getLuMyOrderPage, cancelOrder, getPaySign } from "@/api/service";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
NavHeader
|
||||
NavHeader,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -164,128 +186,64 @@ export default {
|
|||
hasMore: true,
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
// 假数据
|
||||
mockData: {
|
||||
// pending_payment: [
|
||||
// {
|
||||
// id: 1,
|
||||
// orderNo: "ORD20250101001",
|
||||
// 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",
|
||||
// },
|
||||
// ],
|
||||
// 各状态对应的订单列表
|
||||
recordsMap: {
|
||||
pending_payment: [],
|
||||
pending_verification: [],
|
||||
completed: [],
|
||||
cancelled: [],
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
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();
|
||||
},
|
||||
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
|
||||
switchTab(tab) {
|
||||
if (this.currentTab === tab) return;
|
||||
|
|
@ -306,34 +264,60 @@ export default {
|
|||
},
|
||||
// 获取状态文本
|
||||
getStatusText(status) {
|
||||
const statusMap = {
|
||||
pending_payment: "待支付",
|
||||
pending_verification: "待核销",
|
||||
completed: "已完成",
|
||||
cancelled: "已取消",
|
||||
};
|
||||
return statusMap[status] || "";
|
||||
return status === 1
|
||||
? "待支付"
|
||||
: status === 2
|
||||
? "待核销"
|
||||
: status === 3
|
||||
? "已完成"
|
||||
: status === 4
|
||||
? "已取消"
|
||||
: "";
|
||||
},
|
||||
// 获取状态样式类
|
||||
getStatusClass(status) {
|
||||
const classMap = {
|
||||
pending_payment: "status-pending",
|
||||
pending_verification: "status-verification",
|
||||
completed: "status-completed",
|
||||
cancelled: "status-cancelled",
|
||||
};
|
||||
return classMap[status] || "";
|
||||
return status === 1
|
||||
? "status-pending"
|
||||
: status === 2
|
||||
? "status-verification"
|
||||
: status === 3
|
||||
? "status-completed"
|
||||
: status === 4
|
||||
? "status-cancelled"
|
||||
: "";
|
||||
},
|
||||
// 加载数据
|
||||
loadData() {
|
||||
async loadData(append = false) {
|
||||
if (this.loading) return;
|
||||
this.loading = true;
|
||||
// 模拟数据加载
|
||||
setTimeout(() => {
|
||||
const status = this.getStatusValue();
|
||||
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.refreshing = false;
|
||||
this.loadingMore = false;
|
||||
// 这里使用假数据,实际应该调用接口
|
||||
}, 500);
|
||||
}
|
||||
},
|
||||
// 下拉刷新
|
||||
handleRefresh() {
|
||||
|
|
@ -347,12 +331,7 @@ export default {
|
|||
if (this.hasMore && !this.loadingMore && !this.loading) {
|
||||
this.loadingMore = true;
|
||||
this.pageNo += 1;
|
||||
// 模拟加载更多
|
||||
setTimeout(() => {
|
||||
this.loadingMore = false;
|
||||
// 假数据没有更多了
|
||||
this.hasMore = false;
|
||||
}, 500);
|
||||
this.loadData(true);
|
||||
}
|
||||
},
|
||||
// 点击记录项
|
||||
|
|
@ -365,35 +344,95 @@ export default {
|
|||
uni.showModal({
|
||||
title: "提示",
|
||||
content: "确定要取消该订单吗?",
|
||||
success: (res) => {
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
uni.showToast({
|
||||
title: "订单已取消",
|
||||
icon: "success",
|
||||
});
|
||||
// 这里应该调用接口取消订单,然后刷新列表
|
||||
// 暂时从待支付列表中移除
|
||||
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",
|
||||
const res = await cancelOrder({
|
||||
id: item.id,
|
||||
});
|
||||
if (res) {
|
||||
uni.showToast({
|
||||
title: "订单已取消",
|
||||
icon: "success",
|
||||
});
|
||||
this.loadData();
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
// 立即支付
|
||||
handlePay(item) {
|
||||
uni.showToast({
|
||||
title: "该功能正在开发中",
|
||||
icon: "none",
|
||||
// 立即支付(与店铺详情页 handlePay 逻辑一致,跳转收银台小程序)
|
||||
async handlePay(item) {
|
||||
if (!item || !item.orderNumber) {
|
||||
uni.showToast({ title: "订单信息异常", 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) {
|
||||
|
|
@ -514,25 +553,23 @@ export default {
|
|||
background-color: #ffffff;
|
||||
border-radius: 20rpx;
|
||||
margin-bottom: 20rpx;
|
||||
padding: 30rpx;
|
||||
padding: 24rpx 24rpx 20rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
|
||||
|
||||
.record-header {
|
||||
margin-bottom: 24rpx;
|
||||
padding-bottom: 20rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
margin-bottom: 16rpx;
|
||||
|
||||
.record-title-row {
|
||||
.record-shop-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12rpx;
|
||||
margin-bottom: 8rpx;
|
||||
|
||||
.record-title {
|
||||
.shop-name {
|
||||
flex: 1;
|
||||
font-family: PingFang-SC, PingFang-SC;
|
||||
font-weight: bold;
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
font-size: 28rpx;
|
||||
color: #1a1819;
|
||||
}
|
||||
|
||||
|
|
@ -621,47 +658,128 @@ export default {
|
|||
}
|
||||
}
|
||||
}
|
||||
.record-body {
|
||||
background-color: #f8f9fb;
|
||||
border-radius: 16rpx;
|
||||
padding: 18rpx;
|
||||
|
||||
.record-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 20rpx;
|
||||
padding-top: 20rpx;
|
||||
border-top: 1rpx solid #f0f0f0;
|
||||
|
||||
button{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
width: 131rpx;
|
||||
height: 50rpx;
|
||||
border-radius: 10rpx;
|
||||
font-family: PingFang-SC, PingFang-SC;
|
||||
font-weight: 500;
|
||||
font-size: 26rpx;
|
||||
.record-goods {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 16rpx;
|
||||
|
||||
&.cancel-btn {
|
||||
background-color: #f5f5f5;
|
||||
.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;
|
||||
}
|
||||
|
||||
&.pay-btn {
|
||||
.total-amount {
|
||||
margin-left: 4rpx;
|
||||
font-family: PingFang-SC, PingFang-SC;
|
||||
font-weight: 600;
|
||||
font-size: 30rpx;
|
||||
color: #1a1819;
|
||||
}
|
||||
}
|
||||
|
||||
.record-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
|
||||
button {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
min-width: 150rpx;
|
||||
height: 56rpx;
|
||||
padding: 0 20rpx;
|
||||
font-family: PingFang-SC, PingFang-SC;
|
||||
font-weight: 500;
|
||||
font-size: 24rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.pay-btn {
|
||||
background-color: #004294;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
&.detail-btn {
|
||||
.detail-btn {
|
||||
background-color: #f5f5f5;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
&.review-btn {
|
||||
.review-btn {
|
||||
background-color: #004294;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue