Initial commit of akmon project
This commit is contained in:
590
pages/mall/consumer/order-detail.uvue
Normal file
590
pages/mall/consumer/order-detail.uvue
Normal file
@@ -0,0 +1,590 @@
|
||||
<!-- 消费者端 - 订单详情页 -->
|
||||
<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>
|
||||
Reference in New Issue
Block a user