- 移除订单页面冗余的 `onShow` 逻辑,避免重复刷新订单数据 - 调整账单组件中加载状态和类型映射逻辑,简化代码结构 - 修改支付组件备注框高度和 z-index 值,提升用户体验
601 lines
13 KiB
Vue
601 lines
13 KiB
Vue
<template>
|
||
<view class="page flex-col">
|
||
<view class="box_4 flex-col">
|
||
<view class="section_1 flex-col">
|
||
<view class="section_7 flex-row"></view>
|
||
<view class="section_8 flex-row">
|
||
<text class="text_2">{{ title }}</text>
|
||
</view>
|
||
</view>
|
||
<view class="text-wrapper_9 flex-row justify-between">
|
||
<text v-for="(item, index) in tabList" :key="index" :class="[
|
||
'tab-text',
|
||
current === index ? 'tab-active' : 'tab-inactive',
|
||
]" @tap="change({ type: item.type, index })">
|
||
{{ item.name }}
|
||
</text>
|
||
</view>
|
||
</view>
|
||
<view class="box_5 flex-col">
|
||
<!-- 订单列表 -->
|
||
<view v-for="(item, index) in orders" :key="index" class="section_4 flex-col" @tap="detail(item.orderId)">
|
||
<view class="group_3 flex-row justify-between">
|
||
<view class="text-group_3 flex-col justify-between">
|
||
<text class="text_6">{{ item.shop.name }}</text>
|
||
<text class="text_7">下单日期:{{ formatDateTime(item.createTime) }}</text>
|
||
</view>
|
||
<view class="section_9 flex-col justify-between">
|
||
<!-- <view class="text-wrapper_4 flex-col">
|
||
<text
|
||
class="text_8"
|
||
:style="{ color: getStatusColor(item._status._title) }"
|
||
>{{ item._status._title }}</text
|
||
>
|
||
</view> -->
|
||
<view class="text-wrapper_10 flex-row justify-between">
|
||
<text class="text_9">¥</text>
|
||
<text class="text_10">{{ item.payPrice }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 订单商品信息 -->
|
||
<view class="order-goods flex-col">
|
||
<view class="flex goods-item" v-for="(good, goodIndex) in item.cartInfo" :key="goodIndex">
|
||
<image :src="good.image" mode="aspectFill" class="goods-image"></image>
|
||
<view class="flex flex-column goods-info">
|
||
<view class="goods-title">{{ good.title }}</view>
|
||
<view class="goods-spec">{{ good.spec }}</view>
|
||
<view class="goods-price">×{{ good.number }} ¥{{ good.price }}</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 操作按钮 -->
|
||
<!-- 支付按钮 -->
|
||
<view class="group_4 flex-row">
|
||
<view v-if="item.statusDto.type === '0'" class="text-wrapper_6 flex-col action-button"
|
||
@tap.stop="handlePay(item)">
|
||
<text class="text_11">支付</text>
|
||
</view>
|
||
<!-- 发票按钮 -->
|
||
<view v-if="item.statusDto.type === '4'" class="text-wrapper_6 flex-col action-button"
|
||
@tap.stop="handleInvoice(item)">
|
||
<text class="text_11">
|
||
{{
|
||
item.invoiceStatus === "UNREQUESTED"
|
||
? "申请发票"
|
||
: item.invoiceStatus === "REQUESTED"
|
||
? "申请中"
|
||
: item.invoiceStatus === "SUCCESS"
|
||
? "下载发票"
|
||
: "申请失败"
|
||
}}
|
||
</text>
|
||
</view>
|
||
|
||
<view v-if="item.paid > 0 && item.status < 2 && item.refundStatus == 0"
|
||
class="text-wrapper_6 flex-col action-button" @tap.stop="receive(item)">
|
||
<text class="text_11">确认收到餐</text>
|
||
</view>
|
||
<view v-if="item.refundStatus == 2" class="text-wrapper_6 flex-col action-button"
|
||
style="background-color: #f0f0f0;">
|
||
<text class="text_11" style="color: #999;">已退款</text>
|
||
</view>
|
||
|
||
<view class="text-wrapper_6 flex-col action-button detail-button" @tap.stop="detail(item.orderId)">
|
||
<text class="text_11">订单详情</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 空状态 -->
|
||
<uv-empty v-if="orders.length == 0" mode="order"></uv-empty>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, computed } from "vue";
|
||
import { useMainStore } from "@/store/store";
|
||
import { storeToRefs } from "pinia";
|
||
import {
|
||
onLoad,
|
||
onPullDownRefresh,
|
||
onReachBottom,
|
||
onShow,
|
||
} from "@dcloudio/uni-app";
|
||
import { formatDateTime, kmUnit } from "@/utils/util";
|
||
import { orderGetOrders, orderReceive } from "@/api/order";
|
||
import { checkUserInvoiceInfo } from "@/api/invoice";
|
||
import { applyInvoice } from "@/api/order";
|
||
|
||
// 确保导入payUnify方法
|
||
import { payUnify } from "@/api/order";
|
||
import { isWeixin } from "@/utils/util";
|
||
|
||
const main = useMainStore();
|
||
const { member, isLogin } = storeToRefs(main);
|
||
const title = ref("我的订单");
|
||
|
||
const page = ref(1);
|
||
const pageSize = ref(10);
|
||
const orders = ref([]);
|
||
const tabList = ref([
|
||
{
|
||
type: -1,
|
||
name: "全部",
|
||
},
|
||
{
|
||
type: 0,
|
||
name: "待支付",
|
||
},
|
||
{
|
||
type: 1,
|
||
name: "进行中",
|
||
},
|
||
{
|
||
type: 4,
|
||
name: "已完成",
|
||
},
|
||
{
|
||
type: -3,
|
||
name: "退款单",
|
||
},
|
||
]);
|
||
const current = ref(0);
|
||
const type = ref(-1);
|
||
|
||
const goodsNum = computed(() => {
|
||
//计算单个饮品添加到购物车的数量
|
||
return (goods) => {
|
||
let num = 0;
|
||
goods.forEach((good) => (num += parseInt(good.number)));
|
||
return num;
|
||
};
|
||
});
|
||
onLoad(() => {
|
||
if (!isLogin.value) {
|
||
uni.navigateTo({ url: "/pages/components/pages/login/login" });
|
||
}
|
||
if (isLogin.value) {
|
||
getOrders(true); // 每次显示页面时刷新订单数据
|
||
}
|
||
});
|
||
// onShow(() => {
|
||
// if (isLogin.value) {
|
||
// getOrders(true); // 每次显示页面时刷新订单数据
|
||
// }
|
||
// });
|
||
onPullDownRefresh(() => {
|
||
getOrders(true);
|
||
});
|
||
onReachBottom(() => {
|
||
getOrders(false);
|
||
});
|
||
|
||
// tab栏切换
|
||
const change = (e) => {
|
||
console.log("e;", e.type);
|
||
console.log("e.index;", e.index);
|
||
type.value = e.type;
|
||
getOrders(true);
|
||
current.value = e.index;
|
||
};
|
||
|
||
const getOrders = async (isRefresh = false) => {
|
||
uni.showLoading({
|
||
title: "加载中",
|
||
});
|
||
if (isRefresh) {
|
||
orders.value = [];
|
||
page.value = 1;
|
||
}
|
||
let ordersData = await orderGetOrders({
|
||
page: page.value,
|
||
limit: pageSize.value,
|
||
type: type.value,
|
||
});
|
||
|
||
if (ordersData) {
|
||
orders.value = orders.value.concat(ordersData);
|
||
page.value += 1;
|
||
}
|
||
uni.stopPullDownRefresh();
|
||
uni.hideLoading();
|
||
};
|
||
const detail = (id) => {
|
||
uni.navigateTo({
|
||
url: "/pages/components/pages/orders/detail?id=" + id,
|
||
});
|
||
};
|
||
|
||
const handlePay = async (item) => {
|
||
// uni.showLoading({ title: "加载中" });
|
||
|
||
try {
|
||
// 调用支付接口
|
||
let from = "routine";
|
||
// #ifdef H5
|
||
from = "h5";
|
||
if (isWeixin()) {
|
||
from = "wechat";
|
||
}
|
||
// #endif
|
||
|
||
let data = await payUnify({
|
||
uni: item.orderId,
|
||
from: from,
|
||
paytype: "weixin",
|
||
});
|
||
|
||
if (!data) {
|
||
// uni.hideLoading();
|
||
return;
|
||
}
|
||
|
||
if (data.trade_type === "JSAPI") {
|
||
// #ifdef MP-WEIXIN
|
||
uni.requestPayment({
|
||
provider: "wxpay",
|
||
timeStamp: data.data.timeStamp,
|
||
nonceStr: data.data.nonceStr,
|
||
package: data.data.package,
|
||
signType: "MD5",
|
||
paySign: data.data.paySign,
|
||
success: function () {
|
||
uni.showToast({ title: "支付成功" });
|
||
getOrders(true); // 刷新订单列表
|
||
},
|
||
fail: function (err) {
|
||
console.log("支付失败:", err);
|
||
// uni.hideLoading();
|
||
},
|
||
});
|
||
// #endif
|
||
}
|
||
} catch (error) {
|
||
console.error("支付异常:", error);
|
||
// uni.hideLoading();
|
||
}
|
||
};
|
||
|
||
const handleInvoice = async (item) => {
|
||
if (item.invoiceStatus === "UNREQUESTED") {
|
||
// 申请发票
|
||
const checkInvoice = await checkUserInvoiceInfo();
|
||
if (checkInvoice) {
|
||
const res = await applyInvoice(item.orderId);
|
||
if (res) {
|
||
uni.showToast({ title: "发票申请已提交", icon: "success" });
|
||
await getOrders(true); // 刷新订单列表
|
||
}
|
||
} else {
|
||
// 提示用户未填写开发票所需信息
|
||
uni.showToast({
|
||
title: '未填写开发票所需信息,请先填写',
|
||
icon: 'none',
|
||
duration: 1500
|
||
});
|
||
// 2s 后跳转到指定页面
|
||
setTimeout(() => {
|
||
uni.navigateTo({
|
||
url: `/pages/components/pages/invoice/invoice?userId=${member.value.id}`,
|
||
});
|
||
}, 1500);
|
||
}
|
||
|
||
} else if (item.invoiceStatus === "SUCCESS") {
|
||
// 下载发票
|
||
if (item.invoiceAddress) {
|
||
uni.showLoading({
|
||
title: "加载中",
|
||
mask: true,
|
||
});
|
||
uni.downloadFile({
|
||
url: item.invoiceAddress,
|
||
success: (res) => {
|
||
uni.hideLoading();
|
||
if (res.statusCode === 200) {
|
||
uni.openDocument({
|
||
filePath: res.tempFilePath,
|
||
fileType: "pdf",
|
||
showMenu: true,
|
||
});
|
||
}
|
||
},
|
||
fail: (err) => {
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: "发票下载失败",
|
||
icon: "none",
|
||
});
|
||
console.error("下载发票失败:", err);
|
||
},
|
||
});
|
||
}
|
||
}
|
||
};
|
||
// 确认收到货
|
||
const receive = async (order) => {
|
||
let data = await orderReceive({ uni: order.orderId });
|
||
if (data) {
|
||
await getOrders(true);
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style>
|
||
@import "./common.css";
|
||
|
||
.page {
|
||
background-color: rgba(244, 244, 239, 1);
|
||
position: relative;
|
||
width: 750rpx;
|
||
min-height: 100vh;
|
||
overflow-x: hidden;
|
||
}
|
||
|
||
.box_4 {
|
||
background-color: rgba(255, 255, 255, 1);
|
||
width: 750rpx;
|
||
height: 289rpx;
|
||
}
|
||
|
||
.section_1 {
|
||
background-color: rgba(255, 255, 255, 0);
|
||
height: 176rpx;
|
||
width: 750rpx;
|
||
}
|
||
|
||
.section_7 {
|
||
width: 678rpx;
|
||
height: 33rpx;
|
||
margin: 31rpx 0 0 56rpx;
|
||
}
|
||
|
||
.section_8 {
|
||
width: 703rpx;
|
||
height: 64rpx;
|
||
margin: 36rpx 0 12rpx 38rpx;
|
||
}
|
||
|
||
.text_2 {
|
||
width: 120rpx;
|
||
height: 42rpx;
|
||
overflow-wrap: break-word;
|
||
color: rgba(0, 0, 0, 1);
|
||
font-size: 30rpx;
|
||
font-family: PingFang SC-Medium;
|
||
font-weight: 500;
|
||
text-align: center;
|
||
white-space: nowrap;
|
||
line-height: 30rpx;
|
||
margin: 11rpx 0 0 259rpx;
|
||
}
|
||
|
||
.text-wrapper_9 {
|
||
width: 673rpx;
|
||
height: 45rpx;
|
||
margin: 40rpx 0 28rpx 40rpx;
|
||
}
|
||
|
||
.tab-text {
|
||
height: 36rpx;
|
||
overflow-wrap: break-word;
|
||
font-size: 26rpx;
|
||
font-family: PingFang SC-Regular;
|
||
font-weight: normal;
|
||
text-align: left;
|
||
white-space: nowrap;
|
||
line-height: 26rpx;
|
||
}
|
||
|
||
.tab-active {
|
||
color: rgba(34, 34, 34, 0.95);
|
||
font-size: 32rpx;
|
||
font-family: PingFang SC-Medium;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.tab-inactive {
|
||
color: rgba(153, 153, 153, 0.95);
|
||
}
|
||
|
||
.box_5 {
|
||
width: 750rpx;
|
||
min-height: 600rpx;
|
||
padding-bottom: 30rpx;
|
||
}
|
||
|
||
.section_4 {
|
||
background-color: rgba(255, 255, 255, 1);
|
||
border-radius: 24px;
|
||
min-height: 208rpx;
|
||
width: 686rpx;
|
||
margin: 28rpx 0 0 32rpx;
|
||
padding-bottom: 20rpx;
|
||
}
|
||
|
||
.group_3 {
|
||
width: 662rpx;
|
||
height: 120rpx;
|
||
margin-left: 24rpx;
|
||
}
|
||
|
||
.text-group_3 {
|
||
width: 477rpx;
|
||
height: 88rpx;
|
||
margin-top: 32rpx;
|
||
}
|
||
|
||
.text_6 {
|
||
width: 438rpx;
|
||
height: 38rpx;
|
||
overflow-wrap: break-word;
|
||
color: rgba(34, 34, 34, 1);
|
||
font-size: 28rpx;
|
||
font-family: PingFang SC-Medium;
|
||
font-weight: 500;
|
||
text-align: left;
|
||
white-space: nowrap;
|
||
line-height: 28rpx;
|
||
}
|
||
|
||
.text_7 {
|
||
width: 477rpx;
|
||
height: 34rpx;
|
||
overflow-wrap: break-word;
|
||
color: rgba(153, 153, 153, 1);
|
||
font-size: 24rpx;
|
||
font-family: PingFang SC-Regular;
|
||
font-weight: normal;
|
||
text-align: left;
|
||
white-space: nowrap;
|
||
line-height: 24rpx;
|
||
margin-top: 16rpx;
|
||
}
|
||
|
||
.section_9 {
|
||
width: 104rpx;
|
||
height: 96rpx;
|
||
}
|
||
|
||
.text-wrapper_4 {
|
||
background-color: rgba(244, 244, 244, 1);
|
||
border-radius: 0px 24px 8px 0px;
|
||
height: 38rpx;
|
||
border: 1px solid rgba(211, 211, 211, 1);
|
||
width: 104rpx;
|
||
}
|
||
|
||
.text_8 {
|
||
width: 72rpx;
|
||
height: 34rpx;
|
||
overflow-wrap: break-word;
|
||
font-size: 24rpx;
|
||
font-family: PingFang SC-Regular;
|
||
font-weight: normal;
|
||
text-align: left;
|
||
white-space: nowrap;
|
||
line-height: 24rpx;
|
||
margin: 2rpx 0 0 16rpx;
|
||
}
|
||
|
||
.text-wrapper_10 {
|
||
width: 65rpx;
|
||
height: 39rpx;
|
||
margin: 19rpx 0 0 7rpx;
|
||
}
|
||
|
||
.text_9 {
|
||
width: 2rpx;
|
||
height: 39rpx;
|
||
overflow-wrap: break-word;
|
||
color: rgba(0, 0, 0, 1);
|
||
font-size: 20rpx;
|
||
font-family: PingFang SC-Semibold;
|
||
font-weight: 600;
|
||
text-align: right;
|
||
white-space: nowrap;
|
||
padding-right: 20rpx;
|
||
/* line-height: 194rpx; */
|
||
}
|
||
|
||
.text_10 {
|
||
width: auto;
|
||
height: 36rpx;
|
||
overflow-wrap: break-word;
|
||
color: rgba(0, 0, 0, 1);
|
||
font-size: 26rpx;
|
||
font-family: PingFang SC-Semibold;
|
||
font-weight: 600;
|
||
text-align: right;
|
||
white-space: nowrap;
|
||
line-height: 26rpx;
|
||
}
|
||
|
||
.group_4 {
|
||
width: 100%;
|
||
height: 50rpx;
|
||
margin: 6rpx 0 20rpx 0;
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
padding-right: 24rpx;
|
||
}
|
||
|
||
.text-wrapper_6 {
|
||
background-color: rgba(82, 172, 65, 1);
|
||
border-radius: 25px;
|
||
height: 54rpx;
|
||
width: 138rpx;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
}
|
||
|
||
.action-button {
|
||
margin-left: 20rpx;
|
||
}
|
||
|
||
.detail-button {
|
||
background-color: rgba(244, 244, 244, 1);
|
||
}
|
||
|
||
.detail-button .text_11 {
|
||
color: rgba(68, 68, 68, 1);
|
||
}
|
||
|
||
.text_11 {
|
||
width: auto;
|
||
height: 34rpx;
|
||
overflow-wrap: break-word;
|
||
padding: 0 10rpx;
|
||
color: rgba(255, 255, 255, 1);
|
||
font-size: 24rpx;
|
||
font-family: PingFang SC-Medium;
|
||
font-weight: 500;
|
||
text-align: center;
|
||
white-space: nowrap;
|
||
/* line-height: 24rpx; */
|
||
}
|
||
|
||
.order-goods {
|
||
padding: 0 24rpx;
|
||
margin-top: 10rpx;
|
||
}
|
||
|
||
.goods-item {
|
||
margin-bottom: 15rpx;
|
||
}
|
||
|
||
.goods-image {
|
||
width: 100rpx;
|
||
height: 100rpx;
|
||
border-radius: 8rpx;
|
||
margin-right: 20rpx;
|
||
}
|
||
|
||
.goods-info {
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.goods-title {
|
||
font-size: 26rpx;
|
||
color: rgba(34, 34, 34, 1);
|
||
font-weight: 500;
|
||
}
|
||
|
||
.goods-spec {
|
||
font-size: 22rpx;
|
||
color: rgba(153, 153, 153, 1);
|
||
}
|
||
|
||
.goods-price {
|
||
font-size: 22rpx;
|
||
color: rgba(0, 0, 0, 1);
|
||
}
|
||
</style>
|