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.
632 lines
14 KiB
632 lines
14 KiB
<template>
|
|
<view class="after-sale-detail">
|
|
<!-- 状态头部 -->
|
|
<view class="status-header">
|
|
<view
|
|
class="status-badge"
|
|
:class="[getStatusClass(afterSaleDetail.status)]"
|
|
>
|
|
{{ getStatusText(afterSaleDetail.status) }}
|
|
</view>
|
|
<view class="status-desc">{{
|
|
getStatusDesc(afterSaleDetail.status)
|
|
}}</view>
|
|
</view>
|
|
|
|
<!-- 商品信息 -->
|
|
<view class="product-section">
|
|
<view class="section-title">商品信息</view>
|
|
<view class="product-info">
|
|
<image
|
|
class="product-image"
|
|
:src="afterSaleDetail.productImage"
|
|
mode="aspectFill"
|
|
/>
|
|
<view class="product-details">
|
|
<text class="product-title">{{ afterSaleDetail.productTitle }}</text>
|
|
<text class="product-spec">{{ afterSaleDetail.productSpec }}</text>
|
|
<text class="order-number"
|
|
>订单号:{{ afterSaleDetail.orderNumber }}</text
|
|
>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 售后信息 -->
|
|
<view class="after-sale-section">
|
|
<view class="section-title">售后信息</view>
|
|
<view class="info-list">
|
|
<view class="info-item">
|
|
<text class="info-label">售后类型</text>
|
|
<text class="info-value">{{ afterSaleDetail.type }}</text>
|
|
</view>
|
|
<view class="info-item">
|
|
<text class="info-label">售后原因</text>
|
|
<text class="info-value">{{ afterSaleDetail.reason }}</text>
|
|
</view>
|
|
<view class="info-item">
|
|
<text class="info-label">申请时间</text>
|
|
<text class="info-value">{{
|
|
formatTime(afterSaleDetail.createTime)
|
|
}}</text>
|
|
</view>
|
|
<view class="info-item">
|
|
<text class="info-label">售后单号</text>
|
|
<text class="info-value">{{ afterSaleDetail.afterSaleNumber }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 问题描述 -->
|
|
<view class="description-section">
|
|
<view class="section-title">问题描述</view>
|
|
<view class="description-content">
|
|
<text class="description-text">{{ afterSaleDetail.description }}</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 问题图片 -->
|
|
<view
|
|
class="images-section"
|
|
v-if="afterSaleDetail.images && afterSaleDetail.images.length > 0"
|
|
>
|
|
<view class="section-title">问题图片</view>
|
|
<view class="images-grid">
|
|
<image
|
|
class="problem-image"
|
|
v-for="(image, index) in afterSaleDetail.images"
|
|
:key="index"
|
|
:src="image"
|
|
mode="aspectFill"
|
|
@click="previewImage(index)"
|
|
/>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 处理进度 -->
|
|
<view class="progress-section">
|
|
<view class="section-title">处理进度</view>
|
|
<view class="progress-list">
|
|
<view
|
|
class="progress-item"
|
|
v-for="(progress, index) in afterSaleDetail.progressList"
|
|
:key="index"
|
|
:class="{
|
|
active: progress.isActive,
|
|
completed: progress.isCompleted,
|
|
}"
|
|
>
|
|
<view class="progress-icon">
|
|
<uni-icons
|
|
:type="progress.isCompleted ? 'checkmarkempty' : 'circle'"
|
|
size="20"
|
|
:color="progress.isCompleted ? '#34c759' : '#ddd'"
|
|
/>
|
|
</view>
|
|
<view class="progress-content">
|
|
<text class="progress-title">{{ progress.title }}</text>
|
|
<text class="progress-time">{{ formatTime(progress.time) }}</text>
|
|
<text class="progress-desc" v-if="progress.description">{{
|
|
progress.description
|
|
}}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 客服回复 -->
|
|
<view class="reply-section" v-if="afterSaleDetail.reply">
|
|
<view class="section-title">客服回复</view>
|
|
<view class="reply-content">
|
|
<text class="reply-text">{{ afterSaleDetail.reply.content }}</text>
|
|
<text class="reply-time">{{
|
|
formatTime(afterSaleDetail.reply.time)
|
|
}}</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 底部操作 -->
|
|
<view class="bottom-actions" v-if="showBottomActions">
|
|
<button
|
|
class="action-btn secondary"
|
|
@click="cancelAfterSale"
|
|
v-if="afterSaleDetail.status === 'pending'"
|
|
>
|
|
取消申请
|
|
</button>
|
|
<button class="action-btn primary" @click="contactService">
|
|
联系客服
|
|
</button>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
data() {
|
|
return {
|
|
afterSaleId: "",
|
|
afterSaleDetail: {
|
|
id: "",
|
|
status: "pending",
|
|
productImage: "",
|
|
productTitle: "",
|
|
productSpec: "",
|
|
orderNumber: "",
|
|
type: "",
|
|
reason: "",
|
|
description: "",
|
|
images: [],
|
|
createTime: "",
|
|
afterSaleNumber: "",
|
|
progressList: [],
|
|
reply: null,
|
|
},
|
|
};
|
|
},
|
|
computed: {
|
|
showBottomActions() {
|
|
return ["pending", "processing"].includes(this.afterSaleDetail.status);
|
|
},
|
|
},
|
|
onLoad(options) {
|
|
if (options.id) {
|
|
this.afterSaleId = options.id;
|
|
this.loadAfterSaleDetail();
|
|
}
|
|
},
|
|
methods: {
|
|
// 加载售后详情
|
|
async loadAfterSaleDetail() {
|
|
try {
|
|
uni.showLoading({
|
|
title: "加载中...",
|
|
});
|
|
|
|
this.Post(
|
|
{ id: this.afterSaleId },
|
|
"/framework/afterSale/detail",
|
|
"DES"
|
|
)
|
|
.then((res) => {
|
|
uni.hideLoading();
|
|
if (res.code === 200) {
|
|
this.afterSaleDetail = res.data;
|
|
} else {
|
|
uni.showToast({
|
|
title: res.msg || "加载失败",
|
|
icon: "none",
|
|
});
|
|
}
|
|
})
|
|
.catch((error) => {
|
|
uni.hideLoading();
|
|
console.error("加载售后详情失败:", error);
|
|
uni.showToast({
|
|
title: "加载失败",
|
|
icon: "none",
|
|
});
|
|
});
|
|
} catch (error) {
|
|
uni.hideLoading();
|
|
console.error("加载售后详情失败:", error);
|
|
uni.showToast({
|
|
title: "加载失败",
|
|
icon: "none",
|
|
});
|
|
}
|
|
},
|
|
|
|
// 预览图片
|
|
previewImage(index) {
|
|
uni.previewImage({
|
|
current: index,
|
|
urls: this.afterSaleDetail.images,
|
|
});
|
|
},
|
|
|
|
// 取消售后申请
|
|
cancelAfterSale() {
|
|
uni.showModal({
|
|
title: "确认取消",
|
|
content: "确定要取消这个售后申请吗?",
|
|
success: (res) => {
|
|
if (res.confirm) {
|
|
this.Post(
|
|
{ id: this.afterSaleId },
|
|
"/framework/afterSale/cancel",
|
|
"DES"
|
|
)
|
|
.then((res) => {
|
|
if (res.code === 200) {
|
|
uni.showToast({
|
|
title: "取消成功",
|
|
icon: "success",
|
|
});
|
|
// 重新加载详情
|
|
this.loadAfterSaleDetail();
|
|
} else {
|
|
uni.showToast({
|
|
title: res.msg || "取消失败",
|
|
icon: "none",
|
|
});
|
|
}
|
|
})
|
|
.catch((error) => {
|
|
console.error("取消售后申请失败:", error);
|
|
uni.showToast({
|
|
title: "取消失败",
|
|
icon: "none",
|
|
});
|
|
});
|
|
}
|
|
},
|
|
});
|
|
},
|
|
|
|
// 联系客服
|
|
contactService() {
|
|
// 这里可以跳转到客服页面或拨打电话
|
|
uni.showModal({
|
|
title: "联系客服",
|
|
content: "请拨打客服电话:400-123-4567",
|
|
confirmText: "拨打",
|
|
success: (res) => {
|
|
if (res.confirm) {
|
|
// 拨打电话
|
|
uni.makePhoneCall({
|
|
phoneNumber: "400-123-4567",
|
|
});
|
|
}
|
|
},
|
|
});
|
|
},
|
|
|
|
// 获取状态文本
|
|
getStatusText(status) {
|
|
const statusMap = {
|
|
pending: "待处理",
|
|
processing: "处理中",
|
|
completed: "已完成",
|
|
cancelled: "已取消",
|
|
};
|
|
return statusMap[status] || "未知状态";
|
|
},
|
|
|
|
// 获取状态描述
|
|
getStatusDesc(status) {
|
|
const descMap = {
|
|
pending: "您的售后申请已提交,请耐心等待处理",
|
|
processing: "客服正在处理您的售后申请",
|
|
completed: "您的售后申请已处理完成",
|
|
cancelled: "您的售后申请已取消",
|
|
};
|
|
return descMap[status] || "";
|
|
},
|
|
|
|
// 获取状态样式类
|
|
getStatusClass(status) {
|
|
const classMap = {
|
|
pending: "status-pending",
|
|
processing: "status-processing",
|
|
completed: "status-completed",
|
|
cancelled: "status-cancelled",
|
|
};
|
|
return classMap[status] || "status-default";
|
|
},
|
|
|
|
// 格式化时间
|
|
formatTime(time) {
|
|
if (!time) return "";
|
|
const date = new Date(time);
|
|
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(
|
|
2,
|
|
"0"
|
|
)}-${String(date.getDate()).padStart(2, "0")} ${String(
|
|
date.getHours()
|
|
).padStart(2, "0")}:${String(date.getMinutes()).padStart(2, "0")}`;
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.after-sale-detail {
|
|
min-height: 100vh;
|
|
background-color: #f5f5f5;
|
|
padding-bottom: calc(120rpx + env(safe-area-inset-bottom));
|
|
padding-bottom: calc(120rpx + constant(safe-area-inset-bottom));
|
|
}
|
|
|
|
// 状态头部
|
|
.status-header {
|
|
background-color: #fff;
|
|
padding: 40rpx 30rpx;
|
|
text-align: center;
|
|
margin-bottom: 20rpx;
|
|
}
|
|
|
|
.status-badge {
|
|
display: inline-block;
|
|
padding: 12rpx 24rpx;
|
|
border-radius: 20rpx;
|
|
font-size: 28rpx;
|
|
color: #fff;
|
|
font-weight: 600;
|
|
margin-bottom: 16rpx;
|
|
|
|
&.status-pending {
|
|
background-color: #ff9500;
|
|
}
|
|
|
|
&.status-processing {
|
|
background-color: #007aff;
|
|
}
|
|
|
|
&.status-completed {
|
|
background-color: #34c759;
|
|
}
|
|
|
|
&.status-cancelled {
|
|
background-color: #999;
|
|
}
|
|
|
|
&.status-default {
|
|
background-color: #999;
|
|
}
|
|
}
|
|
|
|
.status-desc {
|
|
font-size: 26rpx;
|
|
color: #666;
|
|
line-height: 1.4;
|
|
}
|
|
|
|
// 通用区域样式
|
|
.section-title {
|
|
font-size: 30rpx;
|
|
font-weight: 600;
|
|
color: #333;
|
|
margin-bottom: 24rpx;
|
|
}
|
|
|
|
// 商品信息
|
|
.product-section {
|
|
background-color: #fff;
|
|
padding: 30rpx;
|
|
margin-bottom: 20rpx;
|
|
}
|
|
|
|
.product-info {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
}
|
|
|
|
.product-image {
|
|
width: 120rpx;
|
|
height: 120rpx;
|
|
border-radius: 8rpx;
|
|
margin-right: 20rpx;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.product-details {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.product-title {
|
|
font-size: 30rpx;
|
|
font-weight: 600;
|
|
color: #333;
|
|
margin-bottom: 8rpx;
|
|
line-height: 1.4;
|
|
}
|
|
|
|
.product-spec {
|
|
font-size: 26rpx;
|
|
color: #666;
|
|
margin-bottom: 12rpx;
|
|
}
|
|
|
|
.order-number {
|
|
font-size: 24rpx;
|
|
color: #999;
|
|
}
|
|
|
|
// 售后信息
|
|
.after-sale-section {
|
|
background-color: #fff;
|
|
padding: 30rpx;
|
|
margin-bottom: 20rpx;
|
|
}
|
|
|
|
.info-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 20rpx;
|
|
}
|
|
|
|
.info-item {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
.info-label {
|
|
font-size: 28rpx;
|
|
color: #666;
|
|
min-width: 140rpx;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.info-value {
|
|
font-size: 28rpx;
|
|
color: #333;
|
|
flex: 1;
|
|
text-align: right;
|
|
}
|
|
|
|
// 问题描述
|
|
.description-section {
|
|
background-color: #fff;
|
|
padding: 30rpx;
|
|
margin-bottom: 20rpx;
|
|
}
|
|
|
|
.description-content {
|
|
background-color: #f8f9fa;
|
|
border-radius: 8rpx;
|
|
padding: 20rpx;
|
|
}
|
|
|
|
.description-text {
|
|
font-size: 28rpx;
|
|
color: #333;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
// 问题图片
|
|
.images-section {
|
|
background-color: #fff;
|
|
padding: 30rpx;
|
|
margin-bottom: 20rpx;
|
|
}
|
|
|
|
.images-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(3, 1fr);
|
|
gap: 16rpx;
|
|
}
|
|
|
|
.problem-image {
|
|
width: 100%;
|
|
aspect-ratio: 1;
|
|
border-radius: 8rpx;
|
|
}
|
|
|
|
// 处理进度
|
|
.progress-section {
|
|
background-color: #fff;
|
|
padding: 30rpx;
|
|
margin-bottom: 20rpx;
|
|
}
|
|
|
|
.progress-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 30rpx;
|
|
}
|
|
|
|
.progress-item {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
position: relative;
|
|
|
|
&:not(:last-child)::after {
|
|
content: "";
|
|
position: absolute;
|
|
left: 10rpx;
|
|
top: 40rpx;
|
|
width: 2rpx;
|
|
height: 30rpx;
|
|
background-color: #eee;
|
|
}
|
|
|
|
&.completed:not(:last-child)::after {
|
|
background-color: #34c759;
|
|
}
|
|
}
|
|
|
|
.progress-icon {
|
|
margin-right: 20rpx;
|
|
flex-shrink: 0;
|
|
margin-top: 4rpx;
|
|
}
|
|
|
|
.progress-content {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.progress-title {
|
|
font-size: 28rpx;
|
|
color: #333;
|
|
font-weight: 500;
|
|
margin-bottom: 8rpx;
|
|
}
|
|
|
|
.progress-time {
|
|
font-size: 24rpx;
|
|
color: #999;
|
|
margin-bottom: 8rpx;
|
|
}
|
|
|
|
.progress-desc {
|
|
font-size: 26rpx;
|
|
color: #666;
|
|
line-height: 1.4;
|
|
}
|
|
|
|
// 客服回复
|
|
.reply-section {
|
|
background-color: #fff;
|
|
padding: 30rpx;
|
|
margin-bottom: 20rpx;
|
|
}
|
|
|
|
.reply-content {
|
|
background-color: #f0f8ff;
|
|
border-radius: 8rpx;
|
|
padding: 20rpx;
|
|
}
|
|
|
|
.reply-text {
|
|
font-size: 28rpx;
|
|
color: #333;
|
|
line-height: 1.6;
|
|
margin-bottom: 12rpx;
|
|
display: block;
|
|
}
|
|
|
|
.reply-time {
|
|
font-size: 24rpx;
|
|
color: #999;
|
|
}
|
|
|
|
// 底部操作
|
|
.bottom-actions {
|
|
position: fixed;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
background-color: #fff;
|
|
padding: 20rpx 30rpx;
|
|
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
|
|
border-top: 1rpx solid #eee;
|
|
display: flex;
|
|
gap: 20rpx;
|
|
}
|
|
|
|
.action-btn {
|
|
flex: 1;
|
|
height: 80rpx;
|
|
border-radius: 12rpx;
|
|
font-size: 32rpx;
|
|
font-weight: 600;
|
|
border: none;
|
|
|
|
&.secondary {
|
|
background-color: #fff;
|
|
color: #666;
|
|
border: 1rpx solid #ddd;
|
|
}
|
|
|
|
&.primary {
|
|
background-color: #007aff;
|
|
color: #fff;
|
|
}
|
|
}
|
|
</style>
|
|
|