257 lines
6.1 KiB
Vue
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>
|