You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

1108 lines
24 KiB

<template>
<view class="order-detail-container">
<!-- 订单状态头部 -->
<view class="status-header">
<view class="status-badge" :class="[getStatusClass(orderDetail.status)]">
{{ getStatusText(orderDetail.status) }}
</view>
<view class="order-title">有感商品订单详情</view>
</view>
<!-- 收货地址 -->
<view class="address-section" v-if="orderDetail.receiverArea">
<view class="section-title">收货地址</view>
<view class="address-card">
<view class="address-text">
{{ orderDetail.receiverProvince }}{{ orderDetail.receiverCity
}}{{ orderDetail.receiverArea }}{{ orderDetail.receiverAddress }}
</view>
<view class="contact-info">
<text class="contact-name">{{ orderDetail.receiverName }}</text>
<text class="contact-phone">{{ orderDetail.receiverPhone }}</text>
</view>
</view>
</view>
<!-- 商品列表 -->
<view class="goods-section">
<view class="section-title">商品信息</view>
<view class="goods-list">
<view
class="goods-item"
v-for="goods in orderDetail.orderItems"
:key="goods.id"
>
<view class="goods-image-container">
<image
mode="aspectFill"
:src="goods.specImage"
class="goods-image"
/>
</view>
<view class="goods-content">
<view class="goods-info">
<view class="goods-name">{{ goods.goodsName || "-" }}</view>
<view class="goods-specs">
<view class="spec-tag">
{{ goods.specValueOne }}-{{ goods.specValueTwo }}
</view>
</view>
<view class="goods-quantity-price">
<text class="goods-quantity"
>数量:{{ goods.quantity || 1 }}</text
>
<text class="goods-price">¥{{ goods.price }}</text>
</view>
</view>
</view>
</view>
</view>
<!-- 金额汇总 -->
<view class="amount-summary">
<view class="summary-row">
<text class="summary-label">运费</text>
<text class="summary-value"
>¥{{ orderDetail.shippingFee || "0.00" }}</text
>
</view>
<view class="summary-row">
<text class="summary-label">总金额</text>
<text class="summary-value"
>¥{{ orderDetail.totalAmount || "0.00" }}</text
>
</view>
<view class="summary-row" v-if="orderDetail.usePoints == 0">
<text class="summary-label">积分抵扣</text>
<text class="summary-value"
>-¥{{ orderDetail.pointsDeductAmount || "0.00" }}</text
>
</view>
<view class="summary-row total-row">
<text class="summary-label">应付金额</text>
<text class="summary-value total-amount"
>¥{{ orderDetail.payAmount || "0.00" }}</text
>
</view>
</view>
</view>
<!-- 订单信息 -->
<view class="order-info-section">
<view class="section-title">订单信息</view>
<view class="info-row">
<text class="info-label">订单编号</text>
<text class="info-value" @longpress="copyOrderNo">{{
orderDetail.orderNo
}}</text>
</view>
<view class="info-row">
<text class="info-label">下单时间</text>
<text class="info-value">{{ orderDetail.createTime }}</text>
</view>
<view class="info-row" v-if="orderDetail.payTime">
<text class="info-label">支付时间</text>
<text class="info-value">{{ orderDetail.payTime }}</text>
</view>
<view class="info-row" v-if="orderDetail.shippingTime">
<text class="info-label">发货时间</text>
<text class="info-value">{{ orderDetail.shippingTime }}</text>
</view>
<view class="info-row" v-if="orderDetail.completeTime">
<text class="info-label">完成时间</text>
<text class="info-value">{{ orderDetail.completeTime }}</text>
</view>
<view class="info-row">
<text class="info-label">支付方式</text>
<text class="info-value">{{
orderDetail.payMethod || "在线支付"
}}</text>
</view>
<view class="info-row" v-if="orderDetail.remark">
<text class="info-label">订单备注</text>
<text class="info-value">{{ orderDetail.remark }}</text>
</view>
<view
class="info-row"
v-if="orderDetail.delivery && orderDetail.delivery.expressName"
>
<text class="info-label">快递公司</text>
<text class="info-value">{{ orderDetail.delivery.expressName }}</text>
</view>
<view
class="info-row"
v-if="orderDetail.delivery && orderDetail.delivery.expressCode"
>
<text class="info-label">快递单号</text>
<text class="info-value" @longpress="copyExpressCode">{{
orderDetail.delivery.expressCode
}}</text>
</view>
<view
class="info-row"
v-if="orderDetail.delivery && orderDetail.delivery.expressTime"
>
<text class="info-label">发货时间</text>
<text class="info-value">{{ orderDetail.delivery.expressTime }}</text>
</view>
</view>
<!-- 底部按钮占位div -->
<view class="bottom-placeholder"></view>
<!-- 底部操作 -->
<view class="bottom-actions" v-if="showBottomActions">
<button
class="action-btn-bottom"
@click="handleOrderAction('pay')"
v-if="orderDetail.status === 0"
>
去支付
</button>
<button
class="action-btn-bottom cancel-btn"
@click="handleOrderAction('cancel')"
v-if="orderDetail.status === 0"
>
取消订单
</button>
<!-- <button
class="action-btn-bottom"
@click="handleOrderAction('logistics')"
v-if="[2, 3].includes(orderDetail.status)"
>
查看物流
</button> -->
<button
class="action-btn-bottom confirm-btn"
@click="handleOrderAction('confirm')"
v-if="orderDetail.status === 2"
>
确认收货
</button>
<button
class="action-btn-bottom after-sale-btn"
@click="handleOrderAction('aftersale')"
v-if="orderDetail.status === 3"
>
申请售后
</button>
</view>
<!-- 物流详情弹窗 -->
<view
class="logistics-popup-mask"
v-if="showLogisticsPopup"
@click="closeLogisticsPopup"
>
<view class="logistics-popup" @click.stop>
<view class="popup-header">
<text class="popup-title">物流详情</text>
<text class="popup-close" @click="closeLogisticsPopup">×</text>
</view>
<view class="popup-content">
<!-- 物流状态 -->
<view class="logistics-detail-section">
<view class="detail-title">物流状态</view>
<view class="logistics-status-info">
{{ getLogisticsStatusText(orderDetail.logisticsStatus) }}
</view>
</view>
<!-- 快递信息 -->
<view class="logistics-detail-section">
<view class="detail-title">快递信息</view>
<view class="info-item">
<text class="info-label">快递公司:</text>
<text class="info-value">{{
orderDetail.expressCompany || "--"
}}</text>
</view>
<view class="info-item">
<text class="info-label">快递单号:</text>
<text class="info-value" @longpress="copyExpressNo">{{
orderDetail.expressNo || "--"
}}</text>
</view>
<view class="info-item">
<text class="info-label">发货时间:</text>
<text class="info-value">{{
orderDetail.shippingTime || "--"
}}</text>
</view>
</view>
<!-- 物流轨迹 -->
<view
class="logistics-detail-section"
v-if="logisticsTrace && logisticsTrace.length > 0"
>
<view class="detail-title">物流轨迹</view>
<view class="trace-list">
<view
class="trace-item"
v-for="(trace, index) in logisticsTrace"
:key="index"
:class="{ 'is-current': index === 0 }"
>
<view class="trace-time">{{ trace.time }}</view>
<view class="trace-status">{{ trace.status }}</view>
<view class="trace-location" v-if="trace.location">{{
trace.location
}}</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
orderId: "",
showLogisticsPopup: false,
logisticsTrace: [], // 物流轨迹
orderDetail: {
orderGoods: [],
addressInfo: null,
},
};
},
computed: {
// 是否显示底部操作按钮
showBottomActions() {
return [0, 2, 3].includes(this.orderDetail.status);
},
},
onLoad(options) {
if (options.id) {
this.orderId = options.id;
}
},
onShow() {
this.loadOrderDetail();
},
methods: {
showImgJdsz(img) {
if (!img) return "/static/images/default-goods.png";
if (img.indexOf("https://") != -1 || img.indexOf("http://") != -1) {
return img;
} else {
return this.JDSU_IMG_URL + img;
}
},
// 加载订单详情
async loadOrderDetail() {
try {
this.Post({}, `/framework/ygOrder/getInfo/${this.orderId}`, "DES").then(
(res) => {
if (res.code == 200) {
this.orderDetail = res.data;
} else {
uni.showToast({
title: res.msg,
icon: "none",
});
}
}
);
} catch (error) {
console.error("加载订单详情失败:", error);
uni.showToast({
title: "加载失败",
icon: "none",
});
} finally {
uni.hideLoading();
}
},
// 获取订单状态文本
getStatusText(status) {
const statusMap = {
"-1": "已取消",
0: "待支付",
1: "已支付",
2: "已发货",
3: "已完成",
};
return statusMap[status] || "未知";
},
// 获取状态样式类
getStatusClass(status) {
const classMap = {
"-1": "status-cancelled",
0: "status-pending",
1: "status-paid",
2: "status-shipping",
3: "status-completed",
};
return classMap[status] || "status-default";
},
// 获取物流状态文本
getLogisticsStatusText(status) {
const statusMap = {
0: "待发货",
1: "已发货",
2: "运输中",
3: "派送中",
4: "已签收",
5: "异常",
};
return statusMap[status] || "待发货";
},
// 处理订单操作
handleOrderAction(action) {
switch (action) {
case "pay":
this.goToPay();
break;
case "logistics":
this.showLogisticsDetail();
break;
case "confirm":
this.confirmReceipt();
break;
case "contact":
this.contactSupplier();
break;
case "aftersale":
this.applyAfterSale();
break;
case "cancel":
this.cancelOrder();
break;
}
},
// 取消订单
cancelOrder() {
uni.showModal({
title: "取消订单",
content: "确定要取消该订单吗?",
success: (res) => {
if (res.confirm) {
this.cancelOrderApi();
}
},
});
},
// 取消订单API
cancelOrderApi() {
uni.showLoading({
title: "取消中...",
});
this.Post(
{ parentOrderNo: this.orderDetail.orderNo },
`/framework/ygOrder/cancel`,
"DES"
).then((res) => {
uni.hideLoading();
if (res.code == 200) {
uni.showToast({
title: "订单已取消",
icon: "success",
});
setTimeout(() => {
this.loadOrderDetail();
}, 800);
} else {
uni.showToast({
title: res.msg || "取消订单失败",
icon: "none",
});
}
});
},
// 去支付
goToPay() {
let order = this.orderDetail;
this.Post(
{
method: "POST",
orderNo: order.orderNo,
fromType: 2,
payAmount: order.payAmount,
},
"/framework/wxPay/submitShopPurOrder",
"DES"
).then((res) => {
uni.requestPayment({
nonceStr: res.data.wxInfo.nonceStr,
package: res.data.wxInfo.package,
paySign: res.data.wxInfo.paySign,
signType: res.data.wxInfo.signType,
timeStamp: res.data.wxInfo.timeStamp,
success: () => {
// this.loadOrderDetail();
uni.showToast({
title: "支付成功",
icon: "success",
});
setTimeout(() => {
uni.navigateBack({
delta: 1,
});
}, 800);
},
fail() {
// uni.navigateTo({
// url: '/subPackages/order/trades'
// })
},
});
});
},
// 显示物流详情
showLogisticsDetail() {
if (this.orderDetail.expressNo) {
this.loadLogisticsTrace();
this.showLogisticsPopup = true;
} else {
uni.showToast({
title: "暂无物流信息",
icon: "none",
});
}
},
// 加载物流轨迹
loadLogisticsTrace() {
this.Post(
{
orderId: this.orderId,
expressNo: this.orderDetail.expressNo,
},
"/framework/haveFeeling/order/logistics/trace",
"DES"
).then((res) => {
if (res.code == 200) {
this.logisticsTrace = res.data || [];
}
});
},
// 关闭物流详情弹窗
closeLogisticsPopup() {
this.showLogisticsPopup = false;
},
// 确认收货
confirmReceipt() {
uni.showModal({
title: "确认收货",
content: "确认已收到所有商品吗?",
success: (res) => {
if (res.confirm) {
this.confirmReceiptApi();
}
},
});
},
// 确认收货API
confirmReceiptApi() {
uni.showLoading({
title: "确认中...",
});
this.Post({}, `/framework/ygOrder/finish/${this.orderId}`, "DES").then(
(res) => {
uni.hideLoading();
if (res.code == 200) {
uni.showToast({
title: "确认收货成功",
icon: "success",
});
setTimeout(() => {
this.loadOrderDetail();
}, 800);
} else {
uni.showToast({
title: res.msg || "确认收货失败",
icon: "none",
});
}
}
);
},
// 联系供应商
contactSupplier() {
uni.showToast({
title: "正在联系供应商",
icon: "none",
});
// 这里可以跳转到客服页面或其他联系方式
},
// 申请售后
applyAfterSale() {
// 参考iSoul页面的客服弹窗
uni.showModal({
title: "申请售后",
content:
"客服电话:0515-69186109\n服务时间:周一至周五\n9:00-12:00,13:00-18:00\n\n是否联系客服申请售后?",
confirmText: "联系客服",
success: (res) => {
if (res.confirm) {
// 拨打客服电话
uni.makePhoneCall({
phoneNumber: "0515-69186109",
});
}
},
});
},
// 复制订单号
copyOrderNo() {
uni.setClipboardData({
data: this.orderDetail.orderNo,
success: () => {
uni.showToast({
title: "订单号已复制",
icon: "success",
});
},
});
},
// 复制快递单号
copyExpressCode() {
if (this.orderDetail.delivery && this.orderDetail.delivery.expressCode) {
uni.setClipboardData({
data: this.orderDetail.delivery.expressCode,
success: () => {
uni.showToast({
title: "快递单号已复制",
icon: "success",
});
},
});
}
},
// 复制快递单号
copyExpressNo() {
if (this.orderDetail.expressNo) {
uni.setClipboardData({
data: this.orderDetail.expressNo,
success: () => {
uni.showToast({
title: "快递单号已复制",
icon: "success",
});
},
});
}
},
},
};
</script>
<style lang="scss" scoped>
.order-detail-container {
min-height: 100vh;
background-color: #f5f5f5;
}
// 状态头部
.status-header {
background-color: #fff;
padding: 20rpx 30rpx;
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20rpx;
}
.status-badge {
padding: 8rpx 16rpx;
border-radius: 20rpx;
font-size: 24rpx;
color: #fff;
&.status-pending {
background-color: #ff9500;
}
&.status-paid {
background-color: #007aff;
}
&.status-cancelled {
background-color: #ff3b30;
}
&.status-shipping {
background-color: #34c759;
}
&.status-completed {
background-color: #48bb78;
}
}
.order-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
}
// 通用区域样式
.section-title {
font-size: 28rpx;
font-weight: 600;
color: #333;
margin-bottom: 24rpx;
}
// 收货地址区域
.address-section {
background-color: #fff;
padding: 30rpx;
margin-bottom: 20rpx;
}
.address-card {
background-color: #f8f9fa;
border-radius: 12rpx;
padding: 24rpx;
}
.address-text {
font-size: 26rpx;
color: #333;
line-height: 1.5;
margin-bottom: 16rpx;
}
.contact-info {
display: flex;
gap: 20rpx;
}
.contact-name,
.contact-phone {
font-size: 26rpx;
color: #666;
}
// 商品列表
.goods-section {
background-color: #fff;
padding: 30rpx;
margin-bottom: 20rpx;
}
.goods-item {
display: flex;
align-items: flex-start;
padding: 24rpx 0;
border-bottom: 1rpx solid #f0f0f0;
&:last-child {
border-bottom: none;
}
}
.goods-image-container {
margin-right: 20rpx;
flex-shrink: 0;
}
.goods-image {
width: 100rpx;
height: 100rpx;
border-radius: 10rpx;
}
.goods-content {
flex: 1;
}
.goods-info {
flex: 1;
}
.goods-name {
font-size: 28rpx;
color: #333;
font-weight: 600;
margin-bottom: 8rpx;
line-height: 1.4;
}
.goods-quantity-price {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 10rpx;
}
.goods-quantity {
font-size: 22rpx;
color: #999;
font-weight: 500;
}
.goods-price {
font-size: 26rpx;
color: #f56565;
font-weight: 600;
}
// 商品规格样式
.goods-specs {
display: flex;
flex-wrap: wrap;
gap: 8rpx;
margin-bottom: 10rpx;
}
.spec-tag {
background: #f0f8ff;
border: 1rpx solid #e6f3ff;
border-radius: 12rpx;
padding: 4rpx 12rpx;
display: inline-block;
font-size: 22rpx;
color: #4a90e2;
font-weight: 500;
}
// 金额汇总
.amount-summary {
padding: 20rpx 0;
border-top: 1rpx solid #f0f0f0;
margin-top: 20rpx;
}
.summary-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12rpx;
&:last-child {
margin-bottom: 0;
}
&.total-row {
padding-top: 12rpx;
border-top: 1rpx solid #f0f0f0;
margin-top: 12rpx;
}
}
.summary-label {
font-size: 26rpx;
color: #666;
font-weight: 500;
}
.summary-value {
font-size: 26rpx;
color: #333;
font-weight: 600;
&.total-amount {
font-size: 28rpx;
color: #f56565;
}
}
// 物流信息
.logistics-section {
background-color: #fff;
padding: 30rpx;
margin-bottom: 20rpx;
}
.logistics-card {
display: flex;
align-items: center;
background-color: #f8f9fa;
border-radius: 12rpx;
padding: 24rpx;
}
.logistics-info {
flex: 1;
}
.logistics-company {
margin-bottom: 8rpx;
}
.company-name {
font-size: 26rpx;
color: #333;
font-weight: 600;
margin-right: 12rpx;
}
.express-no {
font-size: 22rpx;
color: #666;
}
.logistics-status {
font-size: 24rpx;
color: #007aff;
}
.logistics-arrow {
margin-left: 20rpx;
}
// 订单信息
.order-info-section {
background-color: #fff;
padding: 30rpx;
margin-bottom: 20rpx;
}
.info-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
&:last-child {
margin-bottom: 0;
}
}
.info-label {
font-size: 26rpx;
color: #666;
}
.info-value {
font-size: 26rpx;
color: #333;
text-align: right;
}
// 底部按钮占位
.bottom-placeholder {
height: 180rpx;
padding-bottom: env(safe-area-inset-bottom);
}
// 底部操作
.bottom-actions {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background-color: #fff;
padding: 20rpx 30rpx;
padding-bottom: calc(20rpx + min(env(safe-area-inset-bottom), 40rpx));
border-top: 1rpx solid #eee;
display: flex;
gap: 16rpx;
.action-btn-bottom {
flex: 1;
border-radius: 10rpx;
font-size: 26rpx;
font-weight: 600;
border: none;
color: #333333;
transition: all 0.3s ease;
text-align: center;
background-color: #77f3f9;
height: 88rpx;
align-items: center;
display: flex;
justify-content: center;
&.confirm-btn {
background-color: #48bb78;
color: #ffffff;
}
&.cancel-btn {
background-color: #ff3b30;
color: #ffffff;
}
&.contact-btn {
background-color: #007aff;
color: #ffffff;
}
&.after-sale-btn {
background-color: #ff4757;
color: #ffffff;
}
}
}
// 物流详情弹窗
.logistics-popup-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
}
.logistics-popup {
width: 650rpx;
max-height: 80vh;
background-color: #fff;
border-radius: 20rpx;
overflow: hidden;
display: flex;
flex-direction: column;
}
.popup-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
border-bottom: 1px solid #f0f0f0;
}
.popup-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.popup-close {
font-size: 40rpx;
color: #999;
}
.popup-content {
padding: 30rpx;
flex: 1;
overflow-y: auto;
}
.logistics-detail-section {
margin-bottom: 30rpx;
&:last-child {
margin-bottom: 0;
}
}
.detail-title {
font-size: 28rpx;
font-weight: 600;
color: #333;
margin-bottom: 16rpx;
border-left: 4rpx solid #007aff;
padding-left: 16rpx;
}
.logistics-status-info {
font-size: 26rpx;
color: #007aff;
font-weight: 500;
}
.info-item {
display: flex;
align-items: center;
margin-bottom: 12rpx;
&:last-child {
margin-bottom: 0;
}
}
.info-label {
font-size: 26rpx;
color: #666;
min-width: 160rpx;
flex-shrink: 0;
}
.info-value {
font-size: 26rpx;
color: #333;
flex: 1;
}
// 物流轨迹
.trace-list {
.trace-item {
padding: 16rpx 0;
border-left: 2rpx solid #e2e8f0;
padding-left: 24rpx;
position: relative;
margin-bottom: 16rpx;
&:before {
content: "";
position: absolute;
left: -6rpx;
top: 20rpx;
width: 10rpx;
height: 10rpx;
border-radius: 50%;
background-color: #e2e8f0;
}
&.is-current {
border-left-color: #007aff;
&:before {
background-color: #007aff;
}
.trace-time,
.trace-status {
color: #007aff;
font-weight: 600;
}
}
&:last-child {
border-left-color: transparent;
}
}
}
.trace-time {
font-size: 22rpx;
color: #999;
margin-bottom: 6rpx;
}
.trace-status {
font-size: 26rpx;
color: #333;
margin-bottom: 4rpx;
}
.trace-location {
font-size: 22rpx;
color: #666;
}
</style>