Files
todo-frontend/src/pages/order/detail.vue
Agent 7a9c31ca27
All checks were successful
continuous-integration/drone/push Build is passing
fix: 增加总面积列宽度
2026-04-02 12:07:02 +00:00

461 lines
10 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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="page" v-if="order">
<!-- 订单信息 -->
<view class="order-header">
<view class="header-row">
<text class="label">订单编号</text>
<text class="value">{{ order.orderNo }}</text>
</view>
<view class="header-row">
<text class="label">订单状态</text>
<text class="status" :class="getStatusClass(order.status)">{{ getStatusText(order.status) }}</text>
</view>
<view class="header-row">
<text class="label">下单时间</text>
<text class="value">{{ formatTime(order.createdAt) }}</text>
</view>
</view>
<!-- 客户信息 -->
<view class="section">
<view class="section-title">客户信息</view>
<view class="section-content">
<view class="info-row">
<text class="label">客户姓名</text>
<text class="value">{{ order.customerName || '散客' }}</text>
</view>
<view class="info-row" v-if="order.customerPhone">
<text class="label">联系电话</text>
<text class="value">{{ order.customerPhone }}</text>
</view>
</view>
</view>
<!-- 商品明细 -->
<view class="section">
<view class="section-title">商品明细</view>
<view class="items-list">
<view class="item-row header">
<text class="item-info">商品信息</text>
<text class="item-area">总面积()</text>
<text class="item-qty">数量</text>
<text class="item-price">单价</text>
<text class="item-subtotal">小计</text>
</view>
<view
v-for="(item, index) in orderItems"
:key="index"
class="item-row"
>
<text class="item-info"><text class="item-name-text">{{ item.productName }}</text><text class="item-spec-text">{{ item.productSpec ? ' ' + item.productSpec : '' }}</text><text class="item-dims-text">{{ item.length || '-' }}x{{ item.width || '-' }}</text></text>
<text class="item-area">{{ calcArea(item) }}</text>
<text class="item-qty">{{ item.quantity }}</text>
<text class="item-price">¥{{ item.price }}</text>
<text class="item-subtotal">¥{{ (item.price * item.quantity).toFixed(0) }}</text>
</view>
</view>
</view>
<!-- 金额信息 -->
<view class="section">
<view class="section-title">金额信息</view>
<view class="section-content">
<view class="info-row">
<text class="label">原价合计</text>
<text class="value">¥{{ order.totalAmount }}</text>
</view>
<view class="info-row">
<text class="label">优惠金额</text>
<text class="value discount">-¥{{ order.discountAmount }}</text>
</view>
<view class="info-row">
<text class="label">实付金额</text>
<text class="value actual">¥{{ order.actualAmount }}</text>
</view>
<view class="info-row" v-if="order.paymentMethod">
<text class="label">支付方式</text>
<text class="value">{{ getPaymentMethod(order.paymentMethod) }}</text>
</view>
<view class="info-row" v-if="order.remark">
<text class="label">备注</text>
<text class="value">{{ order.remark }}</text>
</view>
</view>
</view>
<!-- 操作信息 -->
<view class="section" v-if="order.operatorName">
<view class="section-title">操作信息</view>
<view class="section-content">
<view class="info-row">
<text class="label">操作员</text>
<text class="value">{{ order.operatorName }}</text>
</view>
</view>
</view>
<!-- 底部操作栏 -->
<view class="bottom-bar">
<button class="share-btn" v-if="order.status !== 2" @click="shareOrder">
分享订单
</button>
<button class="print-btn" v-if="order.status !== 2" @click="printOrder">
打印订单
</button>
<button
class="action-btn"
v-if="order.status === 0"
@click="confirmOrder"
>
确认完成
</button>
<button
class="action-btn cancel"
v-if="order.status === 0"
@click="cancelOrder"
>
取消订单
</button>
</view>
</view>
</template>
<script>
import orderApi from '@/api/order'
export default {
data() {
return {
orderId: '',
order: null,
orderItems: []
}
},
onLoad(options) {
if (options.orderId) {
this.orderId = options.orderId
this.loadOrderDetail()
}
},
methods: {
async loadOrderDetail() {
try {
const res = await orderApi.getOrderDetail(this.orderId)
this.order = res.order
this.orderItems = res.items || []
} catch (e) {
uni.showToast({ title: '加载失败', icon: 'none' })
}
},
getStatusClass(status) {
const map = {
1: 'status-success',
2: 'status-cancel',
3: 'status-refunding',
4: 'status-refunded',
9: 'status-returning'
}
return map[status] || ''
},
getStatusText(status) {
const map = {
0: '未完成',
1: '已完成',
2: '已取消',
3: '退款中',
4: '已退款',
9: '退货中'
}
return map[status] || '未知'
},
formatTime(time) {
if (!time) return ''
return time.substring(0, 16).replace('T', ' ')
},
calcArea(item) {
if (item.length && item.width && item.quantity) {
return (item.length * item.width * item.quantity / 1000000).toFixed(4)
}
return '-'
},
getPaymentMethod(method) {
const map = {
'cash': '现金',
'wechat': '微信',
'alipay': '支付宝'
}
return map[method] || method
},
async confirmOrder() {
uni.showModal({
title: '确认订单',
content: '确认完成后订单将变为已完成状态',
success: async (res) => {
if (res.confirm) {
try {
await orderApi.updateOrderStatus(this.orderId, 1)
uni.showToast({ title: '已确认', icon: 'success' })
this.loadOrderDetail()
} catch (e) {
uni.showToast({ title: '操作失败', icon: 'none' })
}
}
}
})
},
async cancelOrder() {
uni.showModal({
title: '取消订单',
content: '确定要取消此订单吗?',
success: async (res) => {
if (res.confirm) {
try {
await orderApi.updateOrderStatus(this.orderId, 2)
uni.showToast({ title: '已取消', icon: 'success' })
this.loadOrderDetail()
} catch (e) {
uni.showToast({ title: '操作失败', icon: 'none' })
}
}
}
})
},
printOrder() {
uni.showToast({ title: '打印功能开发中', icon: 'none' })
},
shareOrder() {
// 构建分享链接包含订单号和客户ID
const h5BaseUrl = import.meta.env.VITE_H5_BASE_URL
const customerId = this.order.customerId || ''
const shareUrl = `${h5BaseUrl}/#/pages/share/order?orderNo=${this.order.orderNo}&customerId=${customerId}`
// 复制链接到剪贴板
uni.setClipboardData({
data: shareUrl,
success: () => {
uni.showModal({
title: '分享链接已复制',
content: '订单分享链接已复制,可粘贴发送给客户',
showCancel: false,
confirmText: '知道了'
})
}
})
},
}
}
</script>
<style>
.page {
min-height: 100vh;
background: #f8f9fa;
padding-bottom: 180rpx;
}
.order-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 30rpx;
color: #fff;
}
.header-row {
display: flex;
justify-content: space-between;
margin-bottom: 16rpx;
}
.header-row .label {
font-size: 26rpx;
opacity: 0.8;
}
.header-row .value {
font-size: 26rpx;
}
.status {
padding: 4rpx 16rpx;
border-radius: 20rpx;
font-size: 24rpx;
}
.status-success {
background: #52c41a;
color: #fff;
}
.status-cancel {
background: #ff4d4f;
color: #fff;
}
.status-returning {
background: #fa8c16;
color: #fff;
}
.section {
background: #fff;
margin: 20rpx;
border-radius: 16rpx;
overflow: hidden;
}
.section-title {
padding: 24rpx 30rpx;
font-size: 28rpx;
font-weight: bold;
color: #333;
border-bottom: 1rpx solid #f0f0f0;
}
.section-content {
padding: 10rpx 30rpx;
}
.info-row {
display: flex;
justify-content: space-between;
padding: 16rpx 0;
border-bottom: 1rpx solid #f8f8f8;
}
.info-row:last-child {
border-bottom: none;
}
.info-row .label {
font-size: 26rpx;
color: #666;
}
.info-row .value {
font-size: 26rpx;
color: #333;
}
.info-row .value.discount {
color: #ff4d4f;
}
.info-row .value.actual {
color: #ff4d4f;
font-weight: bold;
font-size: 30rpx;
}
.items-list {
padding: 0 30rpx;
}
.item-row {
display: flex;
padding: 20rpx 0;
border-bottom: 1rpx solid #f8f8f8;
font-size: 24rpx;
align-items: center;
}
.item-row.header {
font-weight: bold;
color: #666;
background: #f8f9fa;
padding: 16rpx 0;
}
.item-info {
flex: 3;
font-size: 24rpx;
color: #333;
line-height: 1.6;
}
.item-name-text {
color: #333;
font-weight: 500;
}
.item-spec-text {
color: #999;
}
.item-dims-text {
color: #666;
margin-left: 8rpx;
}
.item-area {
flex: 1.5;
text-align: center;
color: #667eea;
font-weight: 500;
}
.item-qty {
flex: 0.8;
text-align: center;
}
.item-price {
flex: 1;
text-align: right;
}
.item-subtotal {
flex: 1;
text-align: right;
color: #ff4d4f;
}
.bottom-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
display: flex;
padding: 20rpx 30rpx;
background: #fff;
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.1);
gap: 20rpx;
}
.print-btn {
flex: 1;
height: 88rpx;
line-height: 88rpx;
background: #fff;
color: #667eea;
border: 2rpx solid #667eea;
border-radius: 44rpx;
font-size: 28rpx;
}
.share-btn {
flex: 1;
height: 88rpx;
line-height: 88rpx;
background: linear-gradient(135deg, #52c41a 0%, #73d13d 100%);
color: #fff;
border: none;
border-radius: 44rpx;
font-size: 28rpx;
}
.action-btn {
flex: 1;
height: 88rpx;
line-height: 88rpx;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #fff;
border: none;
border-radius: 44rpx;
font-size: 28rpx;
}
.action-btn.cancel {
background: #fff;
color: #ff4d4f;
border: 2rpx solid #ff4d4f;
}
</style>