yindongqi 363b620a08 feat(订单): 添加支付功能并调整订单详情显示逻辑
- 在订单页面添加支付按钮,并实现支付逻辑
- 根据订单支付状态调整订单详情页面的显示内容
- 修复购物车栏底部位置,提升用户体验
2025-04-11 14:46:07 +08:00

601 lines
13 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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
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 } from "@dcloudio/uni-app";
import { formatDateTime, kmUnit } from "@/utils/util";
import { orderGetOrders, orderReceive } from "@/api/order";
import { applyInvoice } from "@/api/order";
// 确保导入payUnify方法
import { payUnify } from '@/api/order';
import { isWeixin } from '@/utils/util';
const main = useMainStore();
const { 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" });
}
getOrders(false);
});
onPullDownRefresh(() => {
getOrders(false);
});
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 res = await applyInvoice(item.orderId);
if (res) {
uni.showToast({ title: "发票申请已提交", icon: "success" });
await getOrders(true); // 刷新订单列表
}
} 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>