Files
yxe-mp/pages/order/detail.vue
T
2026-09-29 15:17:13 +08:00

257 lines
6.1 KiB
Vue

<template>
<view class="order-detail-page">
<view class="page-hero">
<AppNavbar title="订单详情" show-back/>
</view>
<view class="card block">
<view class="section-title">订单信息</view>
<view class="info-row">
<view>订单号</view>
<view>{{ getOrderNo(order) }}</view>
</view>
<view class="info-row">
<view>状态</view>
<view class="status">{{ statusLabel(order.status) }}</view>
</view>
<view v-if="order.createTime || order.createdAt" class="info-row">
<view>下单时间</view>
<view>{{ order.createTime || order.createdAt }}</view>
</view>
</view>
<view class="card block">
<view class="section-title">收货地址</view>
<view v-if="receiver.name" class="addr-name">{{ receiver.name }} {{ maskPhone(receiver.phone) }}</view>
<view class="addr-detail">{{ receiver.address }}</view>
</view>
<view class="card block">
<view class="section-title">商品清单</view>
<view v-if="items.length === 0" class="empty">暂无商品</view>
<view v-else class="items">
<view class="item" v-for="(item, idx) in items" :key="idx">
<view class="item-name">{{ item.goods.goodsName }}</view>
<view class="item-meta">x {{ item.num || item.qty || 1 }}</view>
<view class="item-price">¥{{ formatPrice(item.goods.salePrice || item.price || item.amount || 0) }}</view>
</view>
</view>
</view>
<view class="card block">
<view class="section-title">费用明细</view>
<view class="info-row">
<view>商品金额</view>
<view>¥{{ formatPrice(order.totalPrice || 0) }}</view>
</view>
<view class="info-row">
<view>运费</view>
<view>¥{{ formatPrice(order.freightAmount || order.freight || 0) }}</view>
</view>
<view class="info-row">
<view>优惠</view>
<view>-¥{{ formatPrice(order.discountAmount || order.discount || 0) }}</view>
</view>
<view class="info-row total">
<view>应付总额</view>
<view class="pay">¥{{ formatPrice(order.orderPrice || order.payPrice || order.amount || 0) }}</view>
</view>
</view>
</view>
</template>
<script>
import {orderInfoReq} from "@/api/goods";
import AppNavbar from "@/components/AppNavbar.vue";
export default {
components: {AppNavbar},
data() {
return {
order: {},
items: [],
receiver: {
name: '',
phone: '',
address: ''
}
}
},
async onLoad(options) {
const id = options.id
if (id) {
await this.fetchOrder(id)
}
},
methods: {
async fetchOrder(id) {
try {
const {data} = await orderInfoReq(id)
this.order = data || {}
this.items = this.order.goodsList || this.order.items || this.order.orderItems || []
this.receiver = this.getReceiverInfo(this.order)
} catch (err) {
uni.showToast({
title: '订单加载失败',
icon: 'none'
})
}
},
getReceiverInfo(order) {
const address = order.address || order.receiverAddress || order.shippingAddress || {}
const name = order.receiverName || order.name || address.name || ''
const phone = order.receiverPhone || order.phone || address.phone || ''
const fullAddress = order.full_address || order.fullAddress || address.full_address || address.fullAddress || ''
const mergedAddress = fullAddress || `${address.province || ''}${address.city || ''}${address.region || ''}${address.address || ''}`
return {
name,
phone,
address: mergedAddress || '暂无地址'
}
},
getOrderNo(order) {
return order.orderNo || order.order_no || order.no || order.id || ''
},
statusLabel(status) {
if (status === 0 || status === 'pending') return '待支付'
if (status === 1 || status === 'paid') return '待发货'
if (status === 2 || status === 'shipped') return '已发货'
if (status === 3 || status === 'completed') return '已完成'
if (status === 4 || status === 'canceled') return '已取消'
return status || '状态未知'
},
formatPrice(value) {
const num = Number(value || 0)
return num.toFixed(2)
},
maskPhone(phone) {
const value = String(phone || '')
if (value.length < 7) return value
return `${value.slice(0, 3)}****${value.slice(-4)}`
}
}
}
</script>
<style lang="scss" scoped>
.order-detail-page {
min-height: 100vh;
//padding: 0 20rpx 40rpx;
background: #f5f5f5;
}
.page-hero {
//padding: 0 6rpx 18rpx;
background: url('https://yaodongxiao.oss-cn-guangzhou.aliyuncs.com/20260126/462bfa04cf0eff8698884c38b9d17519.png') no-repeat
top center / 100% auto;
}
.page-navbar {
padding: 0 6rpx;
}
.intro-card {
margin-top: 18rpx;
padding: 20rpx 18rpx;
border-radius: 20rpx;
background: rgba(255, 255, 255, 0.9);
box-shadow: 0 10rpx 20rpx rgba(0, 0, 0, 0.08);
}
.card-title {
display: flex;
align-items: center;
gap: 12rpx;
font-size: 28rpx;
font-weight: 700;
color: #1f2937;
}
.title-bar {
width: 6rpx;
height: 30rpx;
border-radius: 999rpx;
background: #2fc6a7;
}
.intro-text {
margin-top: 12rpx;
font-size: 26rpx;
color: #6b7280;
line-height: 1.6;
}
.block {
margin: 18rpx;
}
.info-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10rpx 0;
border-bottom: 1rpx solid #edf1f7;
font-size: 26rpx;
}
.info-row:last-child {
border-bottom: none;
}
.status {
color: var(--brand-primary);
}
.total {
font-weight: 700;
}
.pay {
color: #ff3b30;
font-weight: 700;
}
.addr-name {
font-weight: 700;
color: var(--text-main);
}
.addr-detail {
margin-top: 6rpx;
color: var(--text-sub);
font-size: 24rpx;
}
.items {
display: flex;
flex-direction: column;
gap: 8rpx;
}
.item {
display: flex;
justify-content: space-between;
font-size: 24rpx;
}
.item-name {
color: var(--text-main);
flex: 1;
}
.item-meta {
color: var(--text-sub);
margin: 0 12rpx;
}
.item-price {
color: #ff3b30;
}
.empty {
color: var(--text-sub);
text-align: center;
padding: 16rpx 0;
}
</style>