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.
520 lines
23 KiB
520 lines
23 KiB
<template>
|
|
<div v-loading="state.loading" class="detail-container">
|
|
<el-steps :active="state.currentStep" align-center>
|
|
<el-step
|
|
v-for="(item, index) in [[], state.steps, state.steps2][state.detail.refundType || 0]"
|
|
:key="index"
|
|
:description="item.desc"
|
|
:title="item.title"
|
|
/>
|
|
</el-steps>
|
|
<div class="card">
|
|
<div class="header">
|
|
<h3 class="left red">当前服务单状态:{{ state.detail.refundStatusDesc }}</h3>
|
|
<div class="right">
|
|
<!-- 待处理 -->
|
|
<template v-if="state.detail.refundStatus === 1">
|
|
<el-button type="primary" @click="handleResolveRefundOrReturn">
|
|
同意{{ state.detail.refundType === 1 ? '退款' : '退货' }}
|
|
</el-button>
|
|
<el-button type="danger" @click="handleRejectRefundOrReturn">
|
|
拒绝{{ state.detail.refundType === 1 ? '退款' : '退货' }}
|
|
</el-button>
|
|
</template>
|
|
<!-- 待收货 -->
|
|
<template v-if="state.detail.refundStatus === 4">
|
|
<el-button type="primary" @click="handleResolveReceive">确认收货</el-button>
|
|
<el-button type="danger" @click="handleRejectReceive">拒绝收货</el-button>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
<el-scrollbar class="body">
|
|
<h3>售后商品</h3>
|
|
<el-table border :data="[state.detail.refundProduct]">
|
|
<el-table-column align="center" header-align="center" label="商品图片" prop="productImageUrl">
|
|
<template #default="{ row }">
|
|
<el-image :alt="row.productName || '商品图片'" height="64px" :src="row.productImageUrl" />
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column align="center" header-align="center" label="商品名称" prop="productName" />
|
|
<el-table-column align="center" header-align="center" label="价格" prop="realPrice">
|
|
<template #default="{ row }">¥{{ new Number(row.realPrice).toFixed(2) }}</template>
|
|
</el-table-column>
|
|
<el-table-column align="center" header-align="center" label="属性" prop="skuDescribe" />
|
|
<el-table-column align="center" header-align="center" label="数量" prop="quantity" />
|
|
<el-table-column align="center" header-align="center" label="小计" prop="realAmount">
|
|
<template #default="{ row }">¥{{ new Number(row.realAmount).toFixed(2) }}</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
<h3 class="summary">
|
|
<span>合计:</span>
|
|
<span class="red">¥{{ new Number(state.sum).toFixed(2) }}</span>
|
|
</h3>
|
|
<br />
|
|
<h3>服务单信息</h3>
|
|
<el-form class="half-form" inline label-width="120px">
|
|
<el-form-item class="half" label="服务单号">
|
|
{{ state.detail.refundNo }}
|
|
</el-form-item>
|
|
<el-form-item class="half" label="处理状态">
|
|
{{ state.detail.refundStatusDesc }}
|
|
</el-form-item>
|
|
<el-form-item class="half" label="订单编号">
|
|
{{ state.detail.refundTradeOrderInfo?.orderNo }}
|
|
</el-form-item>
|
|
<el-form-item class="half" label="订单状态">
|
|
{{ state.detail.refundTradeOrderInfo?.orderStatusDesc }}
|
|
</el-form-item>
|
|
<el-form-item label="申请时间">
|
|
{{ state.detail.applyTime }}
|
|
</el-form-item>
|
|
<!-- <el-form-item label="用户账号">
|
|
{{ state.detail.userId }}
|
|
</el-form-item> -->
|
|
<el-form-item label="联系人">
|
|
{{ state.detail.userNickName }}
|
|
</el-form-item>
|
|
<el-form-item label="联系电话">
|
|
{{ state.detail.userPhone }}
|
|
</el-form-item>
|
|
<el-form-item label="退货原因">
|
|
{{ state.detail.refundReason }}
|
|
</el-form-item>
|
|
<el-form-item label="申请退款金额">
|
|
{{ state.detail.applyAmount }}
|
|
</el-form-item>
|
|
<el-form-item label="问题描述">
|
|
{{ state.detail.problemDescribe }}
|
|
</el-form-item>
|
|
<el-form-item label="凭证照片">
|
|
<el-image
|
|
v-for="(item, index) in state.detail.refundEvidences"
|
|
:key="index"
|
|
alt="凭证照片"
|
|
:src="item.fileUrl"
|
|
/>
|
|
</el-form-item>
|
|
</el-form>
|
|
<!-- 仅退款 -->
|
|
<template v-if="state.detail.refundType === 1">
|
|
<h3>退款处理</h3>
|
|
<!-- 待处理 -->
|
|
<el-form
|
|
v-if="state.detail.refundStatus === 1"
|
|
ref="refsForm"
|
|
label-width="120px"
|
|
:model="state.form"
|
|
:rules="state.rules"
|
|
>
|
|
<el-form-item label="订单金额">
|
|
{{ state.detail.refundAmount }}
|
|
</el-form-item>
|
|
<el-form-item label="确认退款金额" prop="refundAmount">
|
|
<el-input-number v-model="state.form.refundAmount" />
|
|
</el-form-item>
|
|
<el-form-item label="处理备注" prop="remark">
|
|
<el-input v-model="state.form.remark" />
|
|
<p class="tips">展示给用户的说明</p>
|
|
</el-form-item>
|
|
</el-form>
|
|
<!-- 已处理 -->
|
|
<el-form v-else label-width="120px">
|
|
<el-form-item label="订单金额">
|
|
{{ state.detail.productAmount }}
|
|
</el-form-item>
|
|
<el-form-item label="退运费">
|
|
{{ state.detail.isBackShippingAmount ? '退运费' : '不退运费' }}
|
|
</el-form-item>
|
|
<el-form-item label="确认退款金额" prop="refundAmount">
|
|
{{ state.detail.refundAmount }}
|
|
</el-form-item>
|
|
<el-form-item label="处理人员">
|
|
{{ state.detail.handleRefundLog?.createUserNickName }}
|
|
</el-form-item>
|
|
<el-form-item label="处理操作">
|
|
{{ state.detail.handleRefundLog?.operationTypeDesc }}
|
|
</el-form-item>
|
|
<el-form-item label="处理时间">
|
|
{{ state.detail.handleRefundLog?.createTime }}
|
|
</el-form-item>
|
|
<el-form-item label="处理备注">
|
|
{{ state.detail.remark || state.detail.closeReason || '无' }}
|
|
</el-form-item>
|
|
</el-form>
|
|
</template>
|
|
<!-- 退货退款 -->
|
|
<template v-else>
|
|
<h3>退货处理</h3>
|
|
<!-- 待处理 -->
|
|
<el-form
|
|
v-if="state.detail.refundStatus === 1"
|
|
ref="refsForm"
|
|
label-width="120px"
|
|
:model="state.form"
|
|
:rules="state.rules"
|
|
>
|
|
<el-form-item label="订单金额">
|
|
{{ state.detail.productAmount }}
|
|
</el-form-item>
|
|
<el-form-item label="退运费" prop="isBackShippingAmount">
|
|
<el-radio-group v-model="state.form.isBackShippingAmount" :opts="opts.shipFees" />
|
|
</el-form-item>
|
|
<el-form-item label="确认退款金额" prop="refundAmount">
|
|
<el-input-number v-model="state.form.refundAmount" />
|
|
</el-form-item>
|
|
<el-form-item label="选择收货点" prop="receivePoint">
|
|
<el-select
|
|
v-model="state.form.receivePoint"
|
|
:config="{ label: 'recipientName', value: 'detailAddress' }"
|
|
:opts="[state.detail.refundAddress]"
|
|
@change="handlePointChange"
|
|
/>
|
|
</el-form-item>
|
|
<el-form-item label="收货人姓名" prop="recipientName">
|
|
<el-input v-model="state.form.recipientName" />
|
|
</el-form-item>
|
|
<el-form-item label="所在区域" prop="address">
|
|
<el-area v-model="state.form.address" v-model:info="state.form.addressInfo" />
|
|
</el-form-item>
|
|
<el-form-item label="详细地址" prop="detailAddress">
|
|
<el-input v-model="state.form.detailAddress" />
|
|
</el-form-item>
|
|
<el-form-item label="联系电话" prop="recipientPhone">
|
|
<el-input v-model="state.form.recipientPhone" />
|
|
</el-form-item>
|
|
<el-form-item label="退货说明" prop="remark">
|
|
<el-input v-model="state.form.remark" />
|
|
<p class="tips">展示给用户的说明</p>
|
|
</el-form-item>
|
|
</el-form>
|
|
<el-form v-else label-width="120px">
|
|
<el-form-item label="订单金额">
|
|
{{ state.detail.productAmount }}
|
|
</el-form-item>
|
|
<el-form-item label="退运费">
|
|
{{ state.detail.isBackShippingAmount ? '退运费' : '不退运费' }}
|
|
</el-form-item>
|
|
<el-form-item label="确认退款金额">
|
|
{{ state.detail.refundAmount }}
|
|
</el-form-item>
|
|
<el-form-item label="收货人姓名">
|
|
{{ state.detail.refundAddress?.recipientName }}
|
|
</el-form-item>
|
|
<el-form-item label="收货地址">
|
|
{{ state.detail.refundAddress?.detailAddress }}
|
|
</el-form-item>
|
|
<el-form-item label="联系电话">
|
|
{{ state.detail.refundAddress?.recipientPhone }}
|
|
</el-form-item>
|
|
<el-form-item label="退货说明">
|
|
{{ state.detail.handleReturnLog?.remark }}
|
|
</el-form-item>
|
|
<el-form-item label="处理人员">
|
|
{{ state.detail.handleReturnLog?.createUserNickName }}
|
|
</el-form-item>
|
|
<el-form-item label="处理操作">
|
|
{{ state.detail.handleReturnLog?.operationTypeDesc }}
|
|
</el-form-item>
|
|
<el-form-item label="处理时间">
|
|
{{ state.detail.handleReturnLog?.createTime }}
|
|
</el-form-item>
|
|
</el-form>
|
|
<template v-if="state.detail.refundLogistics">
|
|
<h3>退货物流</h3>
|
|
<el-form label-width="120px">
|
|
<el-form-item label="物流信息">
|
|
<template v-if="state.detail.refundLogistics">
|
|
<span>
|
|
{{ state.detail.refundLogistics?.companyName }}
|
|
</span>
|
|
<span style="margin: 0 10px">
|
|
{{ state.detail.refundLogistics?.trackingNo }}
|
|
</span>
|
|
<el-button type="text" @click="handleTrack">查看</el-button>
|
|
</template>
|
|
<span v-else>暂无</span>
|
|
</el-form-item>
|
|
<el-form-item label="退款说明">
|
|
{{ state.detail.handleReturnLog?.problemDescribe }}
|
|
</el-form-item>
|
|
<el-form-item label="凭证照片">
|
|
<el-image
|
|
v-for="(item, index) in state.detail.logisticsEvidences"
|
|
:key="index"
|
|
alt="凭证照片"
|
|
:src="item.fileUrl"
|
|
/>
|
|
</el-form-item>
|
|
</el-form>
|
|
</template>
|
|
<template v-if="state.detail.refundStatus === 4">
|
|
<h3>收货处理</h3>
|
|
<el-form ref="refsForm" label-width="120px" :model="state.form" :rules="state.rules">
|
|
<el-form-item label="收货备注" prop="remark">
|
|
<el-input v-model="state.form.remark" />
|
|
</el-form-item>
|
|
</el-form>
|
|
</template>
|
|
</template>
|
|
</el-scrollbar>
|
|
</div>
|
|
<OrderTrack ref="refsOrderTrack" />
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="jsx">
|
|
import OrderTrack from '../order/track.vue';
|
|
const store = useStore();
|
|
const route = useRoute();
|
|
const { proxy } = getCurrentInstance();
|
|
const opts = computed(() => store.state.service.opts);
|
|
if (!unref(opts).init) {
|
|
store.dispatch('service/load');
|
|
}
|
|
const refsForm = ref(null);
|
|
const state = reactive({
|
|
steps: [
|
|
{
|
|
title: '买家申请退款',
|
|
desc: '',
|
|
status: [1, 2],
|
|
},
|
|
{
|
|
title: '商家处理售后申请',
|
|
desc: '未处理',
|
|
status: [5, 6],
|
|
},
|
|
{
|
|
title: '售后完毕',
|
|
desc: '未完毕',
|
|
status: [3, 4, 5, 6],
|
|
},
|
|
],
|
|
steps2: [
|
|
{
|
|
title: '买家申请退货退款',
|
|
desc: '',
|
|
status: [1, 2],
|
|
},
|
|
{
|
|
title: '商家处理售后申请',
|
|
desc: '未处理',
|
|
status: [8, 9],
|
|
},
|
|
{
|
|
title: '买家寄回退货商品',
|
|
desc: '未寄回',
|
|
status: [11],
|
|
},
|
|
{
|
|
title: '商家确认收货',
|
|
desc: '未收货',
|
|
status: [13, 14],
|
|
},
|
|
{
|
|
title: '售后完毕',
|
|
desc: '未完毕',
|
|
status: [3, 4, 7, 10, 12, 13, 14],
|
|
},
|
|
],
|
|
currentStep: 1,
|
|
loading: false,
|
|
detail: {
|
|
refundProduct: [],
|
|
},
|
|
form: {
|
|
reject: false,
|
|
address: [],
|
|
addressInfo: [],
|
|
receivePoint: null,
|
|
isBackShippingAmount: 0,
|
|
area: '',
|
|
areaCode: '',
|
|
city: '',
|
|
cityCode: '',
|
|
detailAddress: '',
|
|
province: '',
|
|
provinceCode: '',
|
|
recipientName: '',
|
|
recipientPhone: '',
|
|
refundAmount: 0,
|
|
refundId: 0,
|
|
remark: '',
|
|
},
|
|
rules: {
|
|
refundAmount: [{ required: true, message: '退款金额不能为空' }],
|
|
recipientName: [{ required: true, message: '收件人姓名不能为空' }],
|
|
address: [{ required: true, message: '所在区域不能为空' }],
|
|
detailAddress: [{ required: true, message: '详细地址不能为空' }],
|
|
recipientPhone: [{ required: true, message: '联系电话不能为空' }],
|
|
remark: [
|
|
{
|
|
validator: (rule, value, cb) => {
|
|
if (state.form.reject && !value) {
|
|
let msg = '不能为空';
|
|
if (state.detail.refundType === 1) {
|
|
msg = '拒绝退款时处理备注' + msg;
|
|
} else {
|
|
if (state.detail.refundStatus === 4) {
|
|
msg = '拒绝收货时收货备注' + msg;
|
|
} else {
|
|
msg = '拒绝退货时处理备注' + msg;
|
|
}
|
|
}
|
|
cb(msg);
|
|
} else {
|
|
cb();
|
|
}
|
|
},
|
|
},
|
|
],
|
|
},
|
|
sum: computed(() => [state.detail.refundProduct].reduce((sum, current) => sum + current.realAmount || 0, 0)),
|
|
});
|
|
const handleLoad = async () => {
|
|
state.loading = true;
|
|
let res = await store.dispatch(
|
|
state.detail.refundType === 1 ? 'service/refundDetail' : 'service/returnDetail',
|
|
route.params.id
|
|
);
|
|
Object.assign(
|
|
state.detail,
|
|
res || {
|
|
refundProduct: [],
|
|
}
|
|
);
|
|
handlePointChange(state.detail.refundAddress.detailAddress);
|
|
state.form.refundId = res.refundId;
|
|
state.form.refundAmount = res.refundAmount;
|
|
[null, state.steps, state.steps2][res.refundType].forEach((step, index) => {
|
|
let date = res.refundLogs.find((item) => step.status.includes(item.operationType));
|
|
step.desc = date?.createTime || step.desc;
|
|
if (date) {
|
|
if (index >= 3) {
|
|
step.desc = date?.operationTypeDesc;
|
|
}
|
|
state.currentStep = index + 1;
|
|
}
|
|
});
|
|
state.loading = false;
|
|
};
|
|
onActivated(handleLoad);
|
|
const handlePointChange = (e) => {
|
|
state.form.receivePoint = e;
|
|
let point = [state.detail.refundAddress].find((item) => item.detailAddress === e);
|
|
state.form.recipientName = point?.recipientName || null;
|
|
state.form.recipientPhone = point?.recipientPhone || null;
|
|
state.form.detailAddress = point?.detailAddress || null;
|
|
state.form.address = point ? [point.provinceCode, point.cityCode, point.areaCode] : [];
|
|
state.form.addressInfo = point ? [point.province, point.city, point.area] : [];
|
|
};
|
|
const refsOrderTrack = ref(null);
|
|
const handleTrack = () => {
|
|
unref(refsOrderTrack).show(state.detail.orderId);
|
|
};
|
|
/* 同意退货/退款 */
|
|
const handleResolveRefundOrReturn = async () => {
|
|
state.loading = true;
|
|
state.form.reject = false;
|
|
try {
|
|
await proxy.$validate(refsForm);
|
|
await store.dispatch(
|
|
state.detail.refundType === 1 ? 'service/resolveRefund' : 'service/resolveReturn',
|
|
state.form
|
|
);
|
|
handleLoad();
|
|
} catch (e) {
|
|
console.info('取消同意', e);
|
|
}
|
|
state.loading = false;
|
|
};
|
|
/* 拒绝退货/退款 */
|
|
const handleRejectRefundOrReturn = async () => {
|
|
state.loading = true;
|
|
state.form.reject = true;
|
|
try {
|
|
await proxy.$validate(refsForm);
|
|
await store.dispatch(
|
|
state.detail.refundType === 1 ? 'service/rejectRefund' : 'service/rejectReturn',
|
|
state.form
|
|
);
|
|
handleLoad();
|
|
} catch (e) {
|
|
console.info('取消拒绝', e);
|
|
}
|
|
state.loading = false;
|
|
};
|
|
/* 确认收货 */
|
|
const handleResolveReceive = async () => {
|
|
state.loading = true;
|
|
state.form.reject = false;
|
|
try {
|
|
await proxy.$validate(refsForm);
|
|
await store.dispatch('service/resolveReceive', state.form);
|
|
handleLoad();
|
|
} catch (e) {
|
|
console.info('取消确认收货', e);
|
|
}
|
|
state.loading = false;
|
|
};
|
|
/* 拒绝收货 */
|
|
const handleRejectReceive = async () => {
|
|
state.loading = true;
|
|
state.form.reject = true;
|
|
try {
|
|
await proxy.$validate(refsForm);
|
|
await store.dispatch('service/rejectReceive', state.form);
|
|
handleLoad();
|
|
} catch (e) {
|
|
console.info('取消拒绝收货', e);
|
|
}
|
|
state.loading = false;
|
|
};
|
|
</script>
|
|
|
|
<style lang="less" scoped>
|
|
.detail-container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
.card {
|
|
height: 100%;
|
|
flex-shrink: 1;
|
|
overflow: hidden;
|
|
margin-top: @layout-space;
|
|
display: flex;
|
|
flex-direction: column;
|
|
.header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
padding: @layout-space;
|
|
}
|
|
.body {
|
|
height: 100%;
|
|
flex-shrink: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
padding: @layout-space;
|
|
h3 {
|
|
margin-bottom: @layout-space;
|
|
}
|
|
.half-form {
|
|
.el-form-item {
|
|
width: 100%;
|
|
&.half {
|
|
width: 50%;
|
|
margin-right: 0;
|
|
}
|
|
}
|
|
}
|
|
.summary {
|
|
text-align: right;
|
|
margin-top: @layout-space;
|
|
}
|
|
}
|
|
.red {
|
|
color: var(--el-color-danger);
|
|
}
|
|
}
|
|
}
|
|
</style>
|