591 lines
14 KiB
Plaintext
591 lines
14 KiB
Plaintext
<!-- 消费者端 - 订单详情页 -->
|
||
<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>
|