8 changed files with 2150 additions and 67 deletions
@ -0,0 +1,612 @@ |
|||||
|
<template> |
||||
|
<view class="after-sale-add"> |
||||
|
<!-- 商品信息卡片 --> |
||||
|
<view class="card-section"> |
||||
|
<view class="card-header"> |
||||
|
<text class="card-title">商品信息</text> |
||||
|
</view> |
||||
|
<view class="product-section"> |
||||
|
<image |
||||
|
class="product-image" |
||||
|
:src="productInfo.image || '/static/image/default-product.png'" |
||||
|
mode="aspectFill" |
||||
|
/> |
||||
|
<view class="product-info"> |
||||
|
<text class="product-title">{{ |
||||
|
productInfo.title || "IP文创公仔" |
||||
|
}}</text> |
||||
|
<text class="product-subtitle">{{ |
||||
|
productInfo.subtitle || "这里是文创公仔的副标题" |
||||
|
}}</text> |
||||
|
<text class="product-desc">{{ |
||||
|
productInfo.description || "介绍" |
||||
|
}}</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 售后表单卡片 --> |
||||
|
<view class="card-section"> |
||||
|
<view class="card-header"> |
||||
|
<text class="card-title">售后信息</text> |
||||
|
</view> |
||||
|
<view class="form-section"> |
||||
|
<!-- 售后类型 --> |
||||
|
<view class="form-item" @click="showTypePopup"> |
||||
|
<text class="form-label">售后类型</text> |
||||
|
<view class="form-value-with-icon"> |
||||
|
<text class="form-value">{{ afterSaleForm.type }}</text> |
||||
|
<uni-icons type="right" size="16" color="#999" /> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 售后原因 --> |
||||
|
<view class="form-item" @click="showReasonPopup"> |
||||
|
<text class="form-label">售后原因</text> |
||||
|
<view class="form-value-with-icon"> |
||||
|
<text class="form-value">{{ afterSaleForm.reason }}</text> |
||||
|
<uni-icons type="right" size="16" color="#999" /> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 理由说明 --> |
||||
|
<view class="form-item"> |
||||
|
<text class="form-label">理由说明</text> |
||||
|
<textarea |
||||
|
class="reason-textarea" |
||||
|
v-model="afterSaleForm.description" |
||||
|
placeholder="请详细描述问题..." |
||||
|
maxlength="500" |
||||
|
/> |
||||
|
<text class="char-count" |
||||
|
>{{ afterSaleForm.description.length }}/500</text |
||||
|
> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 图片上传 --> |
||||
|
<view class="form-item"> |
||||
|
<text class="form-label" |
||||
|
>问题图片 <text class="required">*</text></text |
||||
|
> |
||||
|
<text class="form-sub-label">最多可上传9张图片</text> |
||||
|
<view class="image-upload-section"> |
||||
|
<uni-file-picker |
||||
|
v-model="afterSaleForm.images" |
||||
|
fileMediatype="image" |
||||
|
mode="grid" |
||||
|
:limit="9" |
||||
|
@select="onImageSelect" |
||||
|
@delete="onImageDelete" |
||||
|
/> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 提交按钮 --> |
||||
|
<view class="submit-section"> |
||||
|
<button |
||||
|
class="submit-btn" |
||||
|
@click="submitAfterSale" |
||||
|
:disabled="!canSubmit" |
||||
|
> |
||||
|
提交售后申请 |
||||
|
</button> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 售后类型选择弹窗 --> |
||||
|
<uni-popup ref="typePopup" type="bottom"> |
||||
|
<view class="type-popup"> |
||||
|
<view class="popup-header"> |
||||
|
<text class="popup-title">选择售后类型</text> |
||||
|
<text class="popup-close" @click="closeTypePopup">×</text> |
||||
|
</view> |
||||
|
<view class="popup-content"> |
||||
|
<view |
||||
|
class="type-option" |
||||
|
v-for="(type, index) in typeOptions" |
||||
|
:key="index" |
||||
|
@click="selectType(type)" |
||||
|
> |
||||
|
<view class="type-content"> |
||||
|
<text class="type-text">{{ type.text }}</text> |
||||
|
<uni-icons |
||||
|
v-if="afterSaleForm.type === type.text" |
||||
|
type="checkmarkempty" |
||||
|
size="16" |
||||
|
color="#ff4757" |
||||
|
/> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
<view class="popup-actions"> |
||||
|
<button class="confirm-btn" @click="confirmType">确认</button> |
||||
|
</view> |
||||
|
</view> |
||||
|
</uni-popup> |
||||
|
|
||||
|
<!-- 售后原因选择弹窗 --> |
||||
|
<uni-popup ref="reasonPopup" type="bottom"> |
||||
|
<view class="reason-popup"> |
||||
|
<view class="popup-header"> |
||||
|
<text class="popup-title">选择售后原因</text> |
||||
|
<text class="popup-close" @click="closeReasonPopup">×</text> |
||||
|
</view> |
||||
|
<view class="popup-content"> |
||||
|
<view |
||||
|
class="reason-option" |
||||
|
v-for="(reason, index) in reasonOptions" |
||||
|
:key="index" |
||||
|
@click="selectReason(reason)" |
||||
|
> |
||||
|
<view class="reason-content"> |
||||
|
<text class="reason-text">{{ reason.text }}</text> |
||||
|
<uni-icons |
||||
|
v-if="afterSaleForm.reason === reason.text" |
||||
|
type="checkmarkempty" |
||||
|
size="16" |
||||
|
color="#ff4757" |
||||
|
/> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
<view class="popup-actions"> |
||||
|
<button class="confirm-btn" @click="confirmReason">确认</button> |
||||
|
</view> |
||||
|
</view> |
||||
|
</uni-popup> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
export default { |
||||
|
data() { |
||||
|
return { |
||||
|
productInfo: { |
||||
|
image: "", |
||||
|
title: "IP文创公仔", |
||||
|
subtitle: "这里是文创公仔的副标题", |
||||
|
description: "介绍", |
||||
|
}, |
||||
|
afterSaleForm: { |
||||
|
type: "换货", |
||||
|
reason: "商品质量问题", |
||||
|
description: "", |
||||
|
images: [], |
||||
|
}, |
||||
|
typeOptions: [ |
||||
|
{ text: "换货", value: "exchange" }, |
||||
|
{ text: "仅退款", value: "refund" }, |
||||
|
{ text: "退货", value: "return" }, |
||||
|
], |
||||
|
reasonOptions: [ |
||||
|
{ text: "商品质量问题", value: "quality" }, |
||||
|
{ text: "物流包装破损", value: "damage" }, |
||||
|
{ text: "未收到货", value: "not_received" }, |
||||
|
{ text: "商品与描述不符", value: "mismatch" }, |
||||
|
{ text: "其他原因", value: "other" }, |
||||
|
], |
||||
|
selectedType: null, |
||||
|
selectedReason: null, |
||||
|
}; |
||||
|
}, |
||||
|
computed: { |
||||
|
canSubmit() { |
||||
|
return ( |
||||
|
this.afterSaleForm.description.trim().length > 0 && |
||||
|
this.afterSaleForm.images.length > 0 |
||||
|
); |
||||
|
}, |
||||
|
}, |
||||
|
onLoad(options) { |
||||
|
// 接收商品信息参数 |
||||
|
if (options.productInfo) { |
||||
|
this.productInfo = JSON.parse(decodeURIComponent(options.productInfo)); |
||||
|
} |
||||
|
}, |
||||
|
methods: { |
||||
|
// 显示售后类型选择弹窗 |
||||
|
showTypePopup() { |
||||
|
this.$refs.typePopup.open(); |
||||
|
}, |
||||
|
|
||||
|
// 关闭售后类型选择弹窗 |
||||
|
closeTypePopup() { |
||||
|
this.$refs.typePopup.close(); |
||||
|
}, |
||||
|
|
||||
|
// 选择售后类型 |
||||
|
selectType(type) { |
||||
|
this.selectedType = type; |
||||
|
}, |
||||
|
|
||||
|
// 确认售后类型 |
||||
|
confirmType() { |
||||
|
if (this.selectedType) { |
||||
|
this.afterSaleForm.type = this.selectedType.text; |
||||
|
} |
||||
|
this.closeTypePopup(); |
||||
|
}, |
||||
|
|
||||
|
// 显示售后原因选择弹窗 |
||||
|
showReasonPopup() { |
||||
|
this.$refs.reasonPopup.open(); |
||||
|
}, |
||||
|
|
||||
|
// 关闭售后原因选择弹窗 |
||||
|
closeReasonPopup() { |
||||
|
this.$refs.reasonPopup.close(); |
||||
|
}, |
||||
|
|
||||
|
// 选择售后原因 |
||||
|
selectReason(reason) { |
||||
|
this.selectedReason = reason; |
||||
|
}, |
||||
|
|
||||
|
// 确认售后原因 |
||||
|
confirmReason() { |
||||
|
if (this.selectedReason) { |
||||
|
this.afterSaleForm.reason = this.selectedReason.text; |
||||
|
} |
||||
|
this.closeReasonPopup(); |
||||
|
}, |
||||
|
|
||||
|
// 图片选择回调 |
||||
|
onImageSelect(e) { |
||||
|
console.log("选择图片:", e); |
||||
|
uni.uploadFile({ |
||||
|
url: this.NEWAPIURL_DES + "/system/oss/upload", //仅为示例,非真实的接口地址 |
||||
|
filePath: e.tempFilePaths[0], |
||||
|
name: "file", |
||||
|
|
||||
|
success: (uploadFileRes) => { |
||||
|
console.log(uploadFileRes); |
||||
|
let data = JSON.parse(uploadFileRes.data); |
||||
|
if (data.code == 200) { |
||||
|
this.afterSaleForm.images.push(data.url); |
||||
|
} |
||||
|
}, |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 图片删除回调 |
||||
|
onImageDelete(e) { |
||||
|
console.log("删除图片:", e); |
||||
|
}, |
||||
|
|
||||
|
// 提交售后申请 |
||||
|
async submitAfterSale() { |
||||
|
if (!this.canSubmit) { |
||||
|
uni.showToast({ |
||||
|
title: "请填写理由说明并上传图片", |
||||
|
icon: "none", |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
uni.showLoading({ |
||||
|
title: "提交中...", |
||||
|
}); |
||||
|
|
||||
|
// 构建提交数据 |
||||
|
const submitData = { |
||||
|
productId: this.productInfo.id, |
||||
|
type: this.afterSaleForm.type, |
||||
|
reason: this.afterSaleForm.reason, |
||||
|
description: this.afterSaleForm.description, |
||||
|
images: this.afterSaleForm.images.map( |
||||
|
(item) => item.url || item.path |
||||
|
), |
||||
|
}; |
||||
|
|
||||
|
// 调用售后申请API |
||||
|
this.Post(submitData, "/framework/afterSale/create", "DES") |
||||
|
.then((res) => { |
||||
|
uni.hideLoading(); |
||||
|
if (res.code === 200) { |
||||
|
uni.showToast({ |
||||
|
title: "售后申请提交成功", |
||||
|
icon: "success", |
||||
|
}); |
||||
|
|
||||
|
// 延迟跳转到售后列表 |
||||
|
setTimeout(() => { |
||||
|
uni.redirectTo({ |
||||
|
url: "/subPackages/afterSale/list", |
||||
|
}); |
||||
|
}, 1500); |
||||
|
} 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", |
||||
|
}); |
||||
|
} |
||||
|
}, |
||||
|
}, |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
.after-sale-add { |
||||
|
min-height: 100vh; |
||||
|
background-color: #f8f9fa; |
||||
|
padding: 16rpx; |
||||
|
padding-bottom: calc(120rpx + env(safe-area-inset-bottom)); |
||||
|
padding-bottom: calc(120rpx + constant(safe-area-inset-bottom)); |
||||
|
} |
||||
|
|
||||
|
// 卡片样式 |
||||
|
.card-section { |
||||
|
background-color: #fff; |
||||
|
border-radius: 16rpx; |
||||
|
margin-bottom: 16rpx; |
||||
|
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08); |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
|
||||
|
.card-header { |
||||
|
padding: 20rpx 24rpx; |
||||
|
border-bottom: 1rpx solid #f0f0f0; |
||||
|
background-color: #fafafa; |
||||
|
} |
||||
|
|
||||
|
.card-title { |
||||
|
font-size: 30rpx; |
||||
|
font-weight: 600; |
||||
|
color: #333; |
||||
|
} |
||||
|
|
||||
|
// 商品信息区域 |
||||
|
.product-section { |
||||
|
padding: 24rpx; |
||||
|
display: flex; |
||||
|
align-items: flex-start; |
||||
|
} |
||||
|
|
||||
|
.product-image { |
||||
|
width: 120rpx; |
||||
|
height: 120rpx; |
||||
|
border-radius: 12rpx; |
||||
|
background-color: #f0f0f0; |
||||
|
margin-right: 20rpx; |
||||
|
flex-shrink: 0; |
||||
|
} |
||||
|
|
||||
|
.product-info { |
||||
|
flex: 1; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
} |
||||
|
|
||||
|
.product-title { |
||||
|
font-size: 32rpx; |
||||
|
font-weight: 600; |
||||
|
color: #333; |
||||
|
margin-bottom: 6rpx; |
||||
|
} |
||||
|
|
||||
|
.product-subtitle { |
||||
|
font-size: 26rpx; |
||||
|
color: #666; |
||||
|
margin-bottom: 4rpx; |
||||
|
} |
||||
|
|
||||
|
.product-desc { |
||||
|
font-size: 24rpx; |
||||
|
color: #999; |
||||
|
} |
||||
|
|
||||
|
// 表单区域 |
||||
|
.form-section { |
||||
|
padding: 0; |
||||
|
} |
||||
|
|
||||
|
.form-item { |
||||
|
padding: 20rpx 24rpx; |
||||
|
border-bottom: 1rpx solid #f0f0f0; |
||||
|
|
||||
|
&:last-child { |
||||
|
border-bottom: none; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.form-label { |
||||
|
font-size: 28rpx; |
||||
|
color: #333; |
||||
|
font-weight: 500; |
||||
|
margin-bottom: 12rpx; |
||||
|
display: block; |
||||
|
} |
||||
|
|
||||
|
.required { |
||||
|
color: #ff4757; |
||||
|
font-weight: bold; |
||||
|
} |
||||
|
|
||||
|
.form-sub-label { |
||||
|
font-size: 24rpx; |
||||
|
color: #999; |
||||
|
margin-bottom: 12rpx; |
||||
|
display: block; |
||||
|
} |
||||
|
|
||||
|
.form-value { |
||||
|
font-size: 28rpx; |
||||
|
color: #333; |
||||
|
} |
||||
|
|
||||
|
.form-value-with-icon { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: space-between; |
||||
|
padding: 12rpx 0; |
||||
|
} |
||||
|
|
||||
|
// 理由说明文本框 |
||||
|
.reason-textarea { |
||||
|
width: 100%; |
||||
|
min-height: 120rpx; |
||||
|
max-height: 200rpx; |
||||
|
padding: 16rpx; |
||||
|
border: 1rpx solid #e0e0e0; |
||||
|
border-radius: 12rpx; |
||||
|
font-size: 28rpx; |
||||
|
color: #333; |
||||
|
background-color: #fafafa; |
||||
|
box-sizing: border-box; |
||||
|
resize: none; |
||||
|
} |
||||
|
|
||||
|
.char-count { |
||||
|
font-size: 24rpx; |
||||
|
color: #999; |
||||
|
text-align: right; |
||||
|
margin-top: 8rpx; |
||||
|
display: block; |
||||
|
} |
||||
|
|
||||
|
// 图片上传区域 |
||||
|
.image-upload-section { |
||||
|
margin-top: 12rpx; |
||||
|
} |
||||
|
|
||||
|
// 提交按钮区域 |
||||
|
.submit-section { |
||||
|
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; |
||||
|
box-shadow: 0 -2rpx 12rpx rgba(0, 0, 0, 0.08); |
||||
|
} |
||||
|
|
||||
|
.submit-btn { |
||||
|
width: 100%; |
||||
|
height: 80rpx; |
||||
|
background-color: #ff4757; |
||||
|
color: #fff; |
||||
|
border: none; |
||||
|
border-radius: 12rpx; |
||||
|
font-size: 32rpx; |
||||
|
font-weight: 600; |
||||
|
|
||||
|
&:disabled { |
||||
|
background-color: #ccc; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 售后类型选择弹窗 |
||||
|
.type-popup { |
||||
|
background-color: #fff; |
||||
|
border-radius: 20rpx 20rpx 0 0; |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
|
||||
|
.popup-header { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
padding: 30rpx; |
||||
|
border-bottom: 1rpx solid #f0f0f0; |
||||
|
} |
||||
|
|
||||
|
.popup-title { |
||||
|
font-size: 32rpx; |
||||
|
font-weight: 600; |
||||
|
color: #333; |
||||
|
} |
||||
|
|
||||
|
.popup-close { |
||||
|
font-size: 40rpx; |
||||
|
color: #999; |
||||
|
} |
||||
|
|
||||
|
.popup-content { |
||||
|
max-height: 600rpx; |
||||
|
overflow-y: auto; |
||||
|
} |
||||
|
|
||||
|
.type-option { |
||||
|
padding: 30rpx; |
||||
|
border-bottom: 1rpx solid #f0f0f0; |
||||
|
|
||||
|
&:last-child { |
||||
|
border-bottom: none; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.type-content { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
} |
||||
|
|
||||
|
.type-text { |
||||
|
font-size: 28rpx; |
||||
|
color: #333; |
||||
|
} |
||||
|
|
||||
|
.popup-actions { |
||||
|
padding: 30rpx; |
||||
|
border-top: 1rpx solid #f0f0f0; |
||||
|
} |
||||
|
|
||||
|
.confirm-btn { |
||||
|
width: 100%; |
||||
|
height: 80rpx; |
||||
|
background-color: #ff4757; |
||||
|
color: #fff; |
||||
|
border: none; |
||||
|
border-radius: 12rpx; |
||||
|
font-size: 32rpx; |
||||
|
font-weight: 600; |
||||
|
} |
||||
|
|
||||
|
// 售后原因选择弹窗 |
||||
|
.reason-popup { |
||||
|
background-color: #fff; |
||||
|
border-radius: 20rpx 20rpx 0 0; |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
|
||||
|
.reason-option { |
||||
|
padding: 30rpx; |
||||
|
border-bottom: 1rpx solid #f0f0f0; |
||||
|
|
||||
|
&:last-child { |
||||
|
border-bottom: none; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.reason-content { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
} |
||||
|
|
||||
|
.reason-text { |
||||
|
font-size: 28rpx; |
||||
|
color: #333; |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,632 @@ |
|||||
|
<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> |
@ -0,0 +1,530 @@ |
|||||
|
<template> |
||||
|
<view class="after-sale-list"> |
||||
|
<!-- 状态筛选 --> |
||||
|
<view class="filter-section"> |
||||
|
<view class="filter-tabs"> |
||||
|
<view |
||||
|
class="filter-tab" |
||||
|
:class="{ active: currentStatus === item.value }" |
||||
|
v-for="item in statusOptions" |
||||
|
:key="item.value" |
||||
|
@click="changeStatus(item.value)" |
||||
|
> |
||||
|
<text class="tab-text">{{ item.text }}</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 售后列表 --> |
||||
|
<scroll-view |
||||
|
class="list-scroll" |
||||
|
scroll-y |
||||
|
@scrolltolower="loadMore" |
||||
|
@refresherrefresh="onRefresh" |
||||
|
:refresher-enabled="true" |
||||
|
:refresher-triggered="refresherTriggered" |
||||
|
> |
||||
|
<view class="list-content"> |
||||
|
<view |
||||
|
class="after-sale-item" |
||||
|
v-for="item in afterSaleList" |
||||
|
:key="item.id" |
||||
|
@click="goToDetail(item)" |
||||
|
> |
||||
|
<!-- 商品信息 --> |
||||
|
<view class="product-info"> |
||||
|
<image |
||||
|
class="product-image" |
||||
|
:src="item.productImage" |
||||
|
mode="aspectFill" |
||||
|
/> |
||||
|
<view class="product-details"> |
||||
|
<text class="product-title">{{ item.productTitle }}</text> |
||||
|
<text class="product-spec">{{ item.productSpec }}</text> |
||||
|
<view class="product-meta"> |
||||
|
<text class="order-number">订单号:{{ item.orderNumber }}</text> |
||||
|
<text class="create-time">{{ |
||||
|
formatTime(item.createTime) |
||||
|
}}</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 售后信息 --> |
||||
|
<view class="after-sale-info"> |
||||
|
<view class="info-row"> |
||||
|
<text class="info-label">售后类型:</text> |
||||
|
<text class="info-value">{{ item.type }}</text> |
||||
|
</view> |
||||
|
<view class="info-row"> |
||||
|
<text class="info-label">售后原因:</text> |
||||
|
<text class="info-value">{{ item.reason }}</text> |
||||
|
</view> |
||||
|
<view class="info-row"> |
||||
|
<text class="info-label">申请时间:</text> |
||||
|
<text class="info-value">{{ formatTime(item.createTime) }}</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 状态和操作 --> |
||||
|
<view class="status-section"> |
||||
|
<view class="status-badge" :class="[getStatusClass(item.status)]"> |
||||
|
{{ getStatusText(item.status) }} |
||||
|
</view> |
||||
|
<view class="action-buttons"> |
||||
|
<button |
||||
|
class="action-btn" |
||||
|
@click.stop="cancelAfterSale(item)" |
||||
|
v-if="item.status === 'pending'" |
||||
|
> |
||||
|
取消申请 |
||||
|
</button> |
||||
|
<button class="action-btn primary" @click.stop="goToDetail(item)"> |
||||
|
查看详情 |
||||
|
</button> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 加载更多 --> |
||||
|
<view class="load-more" v-if="hasMore"> |
||||
|
<text class="load-text">加载中...</text> |
||||
|
</view> |
||||
|
<view class="no-more" v-else> |
||||
|
<text class="no-more-text">没有更多数据了</text> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 空状态 --> |
||||
|
<view class="empty-state" v-if="afterSaleList.length === 0 && !loading"> |
||||
|
<image |
||||
|
class="empty-image" |
||||
|
:src="showImg('/uploads/20250808/c16267f9cc2b7a68bf23713b5847987e.png')" |
||||
|
mode="aspectFit" |
||||
|
/> |
||||
|
<text class="empty-text">暂无售后记录</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
</scroll-view> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
export default { |
||||
|
data() { |
||||
|
return { |
||||
|
currentStatus: "all", |
||||
|
statusOptions: [ |
||||
|
{ text: "全部", value: "all" }, |
||||
|
{ text: "待处理", value: "pending" }, |
||||
|
{ text: "处理中", value: "processing" }, |
||||
|
{ text: "已完成", value: "completed" }, |
||||
|
{ text: "已取消", value: "cancelled" }, |
||||
|
], |
||||
|
afterSaleList: [], |
||||
|
page: 1, |
||||
|
pageSize: 10, |
||||
|
hasMore: true, |
||||
|
loading: false, |
||||
|
refresherTriggered: false, |
||||
|
}; |
||||
|
}, |
||||
|
onLoad() { |
||||
|
this.loadAfterSaleList(); |
||||
|
}, |
||||
|
onShow() { |
||||
|
// 页面显示时刷新数据 |
||||
|
this.refreshList(); |
||||
|
}, |
||||
|
methods: { |
||||
|
// 切换状态筛选 |
||||
|
changeStatus(status) { |
||||
|
if (this.currentStatus === status) return; |
||||
|
this.currentStatus = status; |
||||
|
this.resetList(); |
||||
|
this.loadAfterSaleList(); |
||||
|
}, |
||||
|
|
||||
|
// 重置列表 |
||||
|
resetList() { |
||||
|
this.afterSaleList = []; |
||||
|
this.page = 1; |
||||
|
this.hasMore = true; |
||||
|
}, |
||||
|
|
||||
|
// 加载售后列表 |
||||
|
async loadAfterSaleList() { |
||||
|
if (this.loading || !this.hasMore) return; |
||||
|
|
||||
|
try { |
||||
|
this.loading = true; |
||||
|
|
||||
|
const params = { |
||||
|
page: this.page, |
||||
|
pageSize: this.pageSize, |
||||
|
status: this.currentStatus === "all" ? "" : this.currentStatus, |
||||
|
}; |
||||
|
|
||||
|
this.Post(params, "/framework/afterSale/list", "DES") |
||||
|
.then((res) => { |
||||
|
this.loading = false; |
||||
|
if (res.code === 200) { |
||||
|
const newList = res.data.list || []; |
||||
|
|
||||
|
if (this.page === 1) { |
||||
|
this.afterSaleList = newList; |
||||
|
} else { |
||||
|
this.afterSaleList.push(...newList); |
||||
|
} |
||||
|
|
||||
|
this.hasMore = newList.length === this.pageSize; |
||||
|
this.page++; |
||||
|
} else { |
||||
|
uni.showToast({ |
||||
|
title: res.msg || "加载失败", |
||||
|
icon: "none", |
||||
|
}); |
||||
|
} |
||||
|
}) |
||||
|
.catch((error) => { |
||||
|
this.loading = false; |
||||
|
console.error("加载售后列表失败:", error); |
||||
|
uni.showToast({ |
||||
|
title: "加载失败", |
||||
|
icon: "none", |
||||
|
}); |
||||
|
}); |
||||
|
} catch (error) { |
||||
|
this.loading = false; |
||||
|
console.error("加载售后列表失败:", error); |
||||
|
uni.showToast({ |
||||
|
title: "加载失败", |
||||
|
icon: "none", |
||||
|
}); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// 上拉加载更多 |
||||
|
loadMore() { |
||||
|
this.loadAfterSaleList(); |
||||
|
}, |
||||
|
|
||||
|
// 下拉刷新 |
||||
|
onRefresh() { |
||||
|
this.refresherTriggered = true; |
||||
|
this.resetList(); |
||||
|
this.loadAfterSaleList().finally(() => { |
||||
|
this.refresherTriggered = false; |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 刷新列表 |
||||
|
refreshList() { |
||||
|
this.resetList(); |
||||
|
this.loadAfterSaleList(); |
||||
|
}, |
||||
|
|
||||
|
// 跳转到详情页 |
||||
|
goToDetail(item) { |
||||
|
uni.navigateTo({ |
||||
|
url: `/subPackages/afterSale/detail?id=${item.id}`, |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 取消售后申请 |
||||
|
cancelAfterSale(item) { |
||||
|
uni.showModal({ |
||||
|
title: "确认取消", |
||||
|
content: "确定要取消这个售后申请吗?", |
||||
|
success: (res) => { |
||||
|
if (res.confirm) { |
||||
|
this.Post({ id: item.id }, "/framework/afterSale/cancel", "DES") |
||||
|
.then((res) => { |
||||
|
if (res.code === 200) { |
||||
|
uni.showToast({ |
||||
|
title: "取消成功", |
||||
|
icon: "success", |
||||
|
}); |
||||
|
this.refreshList(); |
||||
|
} else { |
||||
|
uni.showToast({ |
||||
|
title: res.msg || "取消失败", |
||||
|
icon: "none", |
||||
|
}); |
||||
|
} |
||||
|
}) |
||||
|
.catch((error) => { |
||||
|
console.error("取消售后申请失败:", error); |
||||
|
uni.showToast({ |
||||
|
title: "取消失败", |
||||
|
icon: "none", |
||||
|
}); |
||||
|
}); |
||||
|
} |
||||
|
}, |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 获取状态文本 |
||||
|
getStatusText(status) { |
||||
|
const statusMap = { |
||||
|
pending: "待处理", |
||||
|
processing: "处理中", |
||||
|
completed: "已完成", |
||||
|
cancelled: "已取消", |
||||
|
}; |
||||
|
return statusMap[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-list { |
||||
|
min-height: 100vh; |
||||
|
background-color: #f5f5f5; |
||||
|
} |
||||
|
|
||||
|
// 筛选区域 |
||||
|
.filter-section { |
||||
|
background-color: #fff; |
||||
|
padding: 20rpx 0; |
||||
|
margin-bottom: 20rpx; |
||||
|
} |
||||
|
|
||||
|
.filter-tabs { |
||||
|
display: flex; |
||||
|
justify-content: space-around; |
||||
|
padding: 0 30rpx; |
||||
|
} |
||||
|
|
||||
|
.filter-tab { |
||||
|
padding: 16rpx 24rpx; |
||||
|
border-radius: 20rpx; |
||||
|
transition: all 0.3s ease; |
||||
|
|
||||
|
&.active { |
||||
|
background-color: #007aff; |
||||
|
|
||||
|
.tab-text { |
||||
|
color: #fff; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.tab-text { |
||||
|
font-size: 28rpx; |
||||
|
color: #666; |
||||
|
font-weight: 500; |
||||
|
} |
||||
|
|
||||
|
// 列表区域 |
||||
|
.list-scroll { |
||||
|
height: calc(100vh - 120rpx); |
||||
|
} |
||||
|
|
||||
|
.list-content { |
||||
|
padding: 0 20rpx; |
||||
|
} |
||||
|
|
||||
|
.after-sale-item { |
||||
|
background-color: #fff; |
||||
|
border-radius: 12rpx; |
||||
|
margin-bottom: 20rpx; |
||||
|
padding: 30rpx; |
||||
|
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06); |
||||
|
} |
||||
|
|
||||
|
// 商品信息 |
||||
|
.product-info { |
||||
|
display: flex; |
||||
|
align-items: flex-start; |
||||
|
margin-bottom: 24rpx; |
||||
|
} |
||||
|
|
||||
|
.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; |
||||
|
} |
||||
|
|
||||
|
.product-meta { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
gap: 4rpx; |
||||
|
} |
||||
|
|
||||
|
.order-number { |
||||
|
font-size: 24rpx; |
||||
|
color: #999; |
||||
|
} |
||||
|
|
||||
|
.create-time { |
||||
|
font-size: 24rpx; |
||||
|
color: #999; |
||||
|
} |
||||
|
|
||||
|
// 售后信息 |
||||
|
.after-sale-info { |
||||
|
background-color: #f8f9fa; |
||||
|
border-radius: 8rpx; |
||||
|
padding: 20rpx; |
||||
|
margin-bottom: 24rpx; |
||||
|
} |
||||
|
|
||||
|
.info-row { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
margin-bottom: 12rpx; |
||||
|
|
||||
|
&:last-child { |
||||
|
margin-bottom: 0; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.info-label { |
||||
|
font-size: 26rpx; |
||||
|
color: #666; |
||||
|
min-width: 140rpx; |
||||
|
flex-shrink: 0; |
||||
|
} |
||||
|
|
||||
|
.info-value { |
||||
|
font-size: 26rpx; |
||||
|
color: #333; |
||||
|
flex: 1; |
||||
|
} |
||||
|
|
||||
|
// 状态和操作 |
||||
|
.status-section { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
} |
||||
|
|
||||
|
.status-badge { |
||||
|
padding: 8rpx 16rpx; |
||||
|
border-radius: 16rpx; |
||||
|
font-size: 24rpx; |
||||
|
color: #fff; |
||||
|
font-weight: 500; |
||||
|
|
||||
|
&.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; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.action-buttons { |
||||
|
display: flex; |
||||
|
gap: 16rpx; |
||||
|
} |
||||
|
|
||||
|
.action-btn { |
||||
|
padding: 12rpx 24rpx; |
||||
|
border-radius: 20rpx; |
||||
|
font-size: 24rpx; |
||||
|
border: 1rpx solid #ddd; |
||||
|
background-color: #fff; |
||||
|
color: #666; |
||||
|
min-width: 120rpx; |
||||
|
|
||||
|
&.primary { |
||||
|
background-color: #007aff; |
||||
|
color: #fff; |
||||
|
border-color: #007aff; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 加载更多 |
||||
|
.load-more, |
||||
|
.no-more { |
||||
|
text-align: center; |
||||
|
padding: 30rpx; |
||||
|
} |
||||
|
|
||||
|
.load-text, |
||||
|
.no-more-text { |
||||
|
font-size: 26rpx; |
||||
|
color: #999; |
||||
|
} |
||||
|
|
||||
|
// 空状态 |
||||
|
.empty-state { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
padding: 100rpx 0; |
||||
|
} |
||||
|
|
||||
|
.empty-image { |
||||
|
width: 200rpx; |
||||
|
height: 200rpx; |
||||
|
margin-bottom: 30rpx; |
||||
|
} |
||||
|
|
||||
|
.empty-text { |
||||
|
font-size: 28rpx; |
||||
|
color: #999; |
||||
|
} |
||||
|
</style> |
Loading…
Reference in new issue