Files
akmon/pages/mall/consumer/order-detail.uvue
2026-01-20 08:04:15 +08:00

591 lines
14 KiB
Plaintext
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="order-detail-page">
<!-- 订单状态 -->
<view class="order-status">
<view class="status-icon">
<text class="status-emoji">{{ getStatusIcon() }}</text>
</view>
<view class="status-info">
<text class="status-text">{{ getStatusText() }}</text>
<text class="status-desc">{{ getStatusDesc() }}</text>
</view>
</view>
<!-- 配送信息 -->
<view v-if="order.status >= 2" class="delivery-info">
<view class="delivery-header">
<text class="delivery-title">配送信息</text>
</view>
<view class="delivery-address">
<view class="address-info">
<text class="recipient">{{ getDeliveryAddress().name }}</text>
<text class="phone">{{ getDeliveryAddress().phone }}</text>
</view>
<text class="address-detail">{{ getDeliveryAddress().detail }}</text>
</view>
<view v-if="deliveryInfo.courier_name" class="courier-info">
<text class="courier-label">配送员:</text>
<text class="courier-name">{{ deliveryInfo.courier_name }}</text>
<text class="courier-phone">{{ deliveryInfo.courier_phone }}</text>
</view>
</view>
<!-- 商品信息 -->
<view class="order-products">
<view class="shop-header">
<text class="shop-name">{{ merchant.shop_name }}</text>
</view>
<view v-for="item in orderItems" :key="item.id" class="product-item">
<image :src="item.product_image || '/static/default-product.png'" class="product-image" />
<view class="product-info">
<text class="product-name">{{ item.product_name }}</text>
<text v-if="item.sku_specifications" class="product-spec">{{ getSpecText(item.sku_specifications) }}</text>
<view class="price-quantity">
<text class="product-price">¥{{ item.price }}</text>
<text class="product-quantity">×{{ item.quantity }}</text>
</view>
</view>
</view>
</view>
<!-- 订单信息 -->
<view class="order-info">
<view class="info-row">
<text class="info-label">订单编号</text>
<text class="info-value">{{ order.order_no }}</text>
</view>
<view class="info-row">
<text class="info-label">下单时间</text>
<text class="info-value">{{ formatTime(order.created_at) }}</text>
</view>
<view class="info-row">
<text class="info-label">支付方式</text>
<text class="info-value">{{ getPaymentMethodText() }}</text>
</view>
</view>
<!-- 费用明细 -->
<view class="cost-detail">
<view class="cost-row">
<text class="cost-label">商品总额</text>
<text class="cost-value">¥{{ order.total_amount }}</text>
</view>
<view class="cost-row">
<text class="cost-label">优惠金额</text>
<text class="cost-value">-¥{{ order.discount_amount }}</text>
</view>
<view class="cost-row">
<text class="cost-label">配送费</text>
<text class="cost-value">¥{{ order.delivery_fee }}</text>
</view>
<view class="cost-row total">
<text class="cost-label">实付金额</text>
<text class="cost-value">¥{{ order.actual_amount }}</text>
</view>
</view>
<!-- 底部操作 -->
<view class="bottom-actions">
<button v-if="order.status === 1" class="pay-btn" @click="payOrder">立即支付</button>
<button v-if="order.status === 2" class="remind-btn" @click="remindDelivery">提醒发货</button>
<button v-if="order.status === 3" class="confirm-btn" @click="confirmReceive">确认收货</button>
<button v-if="order.status === 4" class="review-btn" @click="goToReview">评价商品</button>
<button v-if="order.status <= 2" class="cancel-btn" @click="cancelOrder">取消订单</button>
<button class="service-btn" @click="contactService">联系客服</button>
</view>
</view>
</template>
<script>
import { OrderType, OrderItemType, MerchantType } from '@/types/mall-types.uts'
export default {
data() {
return {
order: {
id: '',
order_no: '',
user_id: '',
merchant_id: '',
status: 0,
total_amount: 0,
discount_amount: 0,
delivery_fee: 0,
actual_amount: 0,
payment_method: 0,
payment_status: 0,
delivery_address: {},
created_at: ''
} as OrderType,
orderItems: [] as Array<OrderItemType & { product_image: string }>,
merchant: {
id: '',
user_id: '',
shop_name: '',
shop_logo: '',
shop_banner: '',
shop_description: '',
contact_name: '',
contact_phone: '',
shop_status: 0,
rating: 0,
total_sales: 0,
created_at: ''
} as MerchantType,
deliveryInfo: {
courier_name: '',
courier_phone: '',
tracking_no: ''
}
}
},
onLoad(options: any) {
const orderId = options.orderId as string
if (orderId) {
this.loadOrderDetail(orderId)
}
},
methods: {
loadOrderDetail(orderId: string) {
// 模拟加载订单详情数据
this.order = {
id: orderId,
order_no: 'ORD202401150001',
user_id: 'user_001',
merchant_id: 'merchant_001',
status: 3, // 1:待支付 2:待发货 3:待收货 4:已完成 5:已取消
total_amount: 299.98,
discount_amount: 30.00,
delivery_fee: 8.00,
actual_amount: 277.98,
payment_method: 1, // 1:微信支付 2:支付宝 3:余额
payment_status: 1,
delivery_address: {
name: '张三',
phone: '13800138000',
detail: '北京市朝阳区某某街道某某小区1号楼101室'
},
created_at: '2024-01-15 14:30:00'
}
this.orderItems = [
{
id: 'item_001',
order_id: orderId,
product_id: 'product_001',
sku_id: 'sku_001',
product_name: '精选好物商品',
sku_specifications: { color: '红色', size: 'M' },
price: 199.99,
quantity: 1,
total_amount: 199.99,
product_image: '/static/product1.jpg'
},
{
id: 'item_002',
order_id: orderId,
product_id: 'product_002',
sku_id: 'sku_002',
product_name: '优质配件',
sku_specifications: { type: '标准版' },
price: 99.99,
quantity: 1,
total_amount: 99.99,
product_image: '/static/product2.jpg'
}
]
this.merchant = {
id: 'merchant_001',
user_id: 'user_001',
shop_name: '优质好店',
shop_logo: '/static/shop-logo.png',
shop_banner: '/static/shop-banner.png',
shop_description: '专注品质生活',
contact_name: '店主小王',
contact_phone: '13800138000',
shop_status: 1,
rating: 4.8,
total_sales: 15680,
created_at: '2023-06-01'
}
if (this.order.status >= 3) {
this.deliveryInfo = {
courier_name: '李师傅',
courier_phone: '13900139000',
tracking_no: 'YT123456789'
}
}
},
getStatusIcon(): string {
const icons = ['⏳', '💰', '📦', '🚚', '✅', '❌']
return icons[this.order.status] || '⏳'
},
getStatusText(): string {
const statusTexts = ['订单异常', '待支付', '待发货', '待收货', '已完成', '已取消']
return statusTexts[this.order.status] || '未知状态'
},
getStatusDesc(): string {
const statusDescs = [
'订单状态异常',
'请在24小时内完成支付',
'商家正在准备发货',
'商品正在配送中,请耐心等待',
'订单已完成,感谢您的购买',
'订单已取消'
]
return statusDescs[this.order.status] || ''
},
getDeliveryAddress(): any {
return this.order.delivery_address as any
},
getSpecText(specifications: any): string {
if (!specifications) return ''
return Object.keys(specifications).map(key => `${key}: ${specifications[key]}`).join(', ')
},
formatTime(timeStr: string): string {
return timeStr.replace('T', ' ').split('.')[0]
},
getPaymentMethodText(): string {
const methods = ['', '微信支付', '支付宝', '余额支付']
return methods[this.order.payment_method || 0] || '未知'
},
payOrder() {
uni.showModal({
title: '确认支付',
content: `确认支付 ¥${this.order.actual_amount} 吗?`,
success: (res) => {
if (res.confirm) {
// 模拟支付
uni.showLoading({ title: '支付中...' })
setTimeout(() => {
uni.hideLoading()
this.order.status = 2
uni.showToast({
title: '支付成功',
icon: 'success'
})
}, 2000)
}
}
})
},
remindDelivery() {
uni.showToast({
title: '已提醒商家发货',
icon: 'success'
})
},
confirmReceive() {
uni.showModal({
title: '确认收货',
content: '确认已收到商品吗?',
success: (res) => {
if (res.confirm) {
this.order.status = 4
uni.showToast({
title: '确认收货成功',
icon: 'success'
})
}
}
})
},
goToReview() {
uni.navigateTo({
url: `/pages/mall/consumer/product-review?orderId=${this.order.id}`
})
},
cancelOrder() {
uni.showModal({
title: '取消订单',
content: '确定要取消这个订单吗?',
success: (res) => {
if (res.confirm) {
this.order.status = 5
uni.showToast({
title: '订单已取消',
icon: 'success'
})
}
}
})
},
contactService() {
uni.navigateTo({
url: `/pages/mall/service/chat?orderId=${this.order.id}`
})
}
}
}
</script>
<style>
.order-detail-page {
background-color: #f5f5f5;
min-height: 100vh;
padding-bottom: 120rpx;
}
.order-status {
background-color: #fff;
padding: 40rpx 30rpx;
margin-bottom: 20rpx;
display: flex;
align-items: center;
}
.status-icon {
width: 100rpx;
height: 100rpx;
background-color: #f0f8ff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 30rpx;
}
.status-emoji {
font-size: 48rpx;
}
.status-info {
flex: 1;
}
.status-text {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 10rpx;
}
.status-desc {
font-size: 26rpx;
color: #666;
}
.delivery-info {
background-color: #fff;
padding: 30rpx;
margin-bottom: 20rpx;
}
.delivery-header {
margin-bottom: 20rpx;
}
.delivery-title {
font-size: 30rpx;
font-weight: bold;
color: #333;
}
.delivery-address {
padding: 20rpx 0;
border-bottom: 1rpx solid #f5f5f5;
}
.address-info {
display: flex;
margin-bottom: 10rpx;
}
.recipient {
font-size: 28rpx;
color: #333;
margin-right: 30rpx;
}
.phone {
font-size: 28rpx;
color: #666;
}
.address-detail {
font-size: 26rpx;
color: #666;
line-height: 1.4;
}
.courier-info {
padding: 20rpx 0;
display: flex;
align-items: center;
}
.courier-label {
font-size: 26rpx;
color: #666;
margin-right: 10rpx;
}
.courier-name {
font-size: 26rpx;
color: #333;
margin-right: 30rpx;
}
.courier-phone {
font-size: 26rpx;
color: #007aff;
}
.order-products {
background-color: #fff;
margin-bottom: 20rpx;
}
.shop-header {
padding: 20rpx 30rpx;
border-bottom: 1rpx solid #f5f5f5;
}
.shop-name {
font-size: 28rpx;
color: #333;
}
.product-item {
display: flex;
padding: 30rpx;
border-bottom: 1rpx solid #f5f5f5;
}
.product-item:last-child {
border-bottom: none;
}
.product-image {
width: 120rpx;
height: 120rpx;
border-radius: 10rpx;
margin-right: 20rpx;
}
.product-info {
flex: 1;
}
.product-name {
font-size: 28rpx;
color: #333;
margin-bottom: 10rpx;
line-height: 1.3;
}
.product-spec {
font-size: 24rpx;
color: #999;
margin-bottom: 15rpx;
}
.price-quantity {
display: flex;
justify-content: space-between;
align-items: center;
}
.product-price {
font-size: 28rpx;
color: #ff4444;
font-weight: bold;
}
.product-quantity {
font-size: 26rpx;
color: #666;
}
.order-info, .cost-detail {
background-color: #fff;
padding: 30rpx;
margin-bottom: 20rpx;
}
.info-row, .cost-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15rpx 0;
}
.info-label, .cost-label {
font-size: 28rpx;
color: #666;
}
.info-value, .cost-value {
font-size: 28rpx;
color: #333;
}
.cost-row.total {
border-top: 1rpx solid #f5f5f5;
margin-top: 10rpx;
padding-top: 20rpx;
}
.cost-row.total .cost-label,
.cost-row.total .cost-value {
font-weight: bold;
color: #ff4444;
}
.bottom-actions {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background-color: #fff;
padding: 20rpx 30rpx;
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.1);
display: flex;
gap: 20rpx;
}
.bottom-actions button {
flex: 1;
height: 70rpx;
border-radius: 35rpx;
font-size: 26rpx;
border: none;
}
.pay-btn, .confirm-btn {
background-color: #ff4444;
color: #fff;
}
.remind-btn, .review-btn {
background-color: #ffa726;
color: #fff;
}
.cancel-btn {
background-color: #f5f5f5;
color: #666;
}
.service-btn {
background-color: #007aff;
color: #fff;
}
</style>