mirror of
https://gitee.com/beijing_hongye_huicheng/lilishop-ui.git
synced 2026-08-06 19:07:25 +08:00
feat: 新增全局布局样式并提升组件响应式表现
- 在 global-layout.scss 中引入全局布局样式,统一页面宽度与对齐方式 - 更新多个组件与页面以优化响应式,包括宽度、间距及 flex 布局等调整 - 在 API 请求中增加 loading 状态管理,改善用户体验 - 优化领券中心与商品详情页,提升功能与 UI 一致性
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
class="search-form"
|
||||
@keyup.enter="handleSearch"
|
||||
>
|
||||
<el-form-item label="关键字" prop="keywords" style="display: block; width: 100%">
|
||||
<el-form-item label="关键字" prop="keywords">
|
||||
<el-input
|
||||
v-model="searchForm.keywords"
|
||||
placeholder="请输入商品名称、订单编号搜索"
|
||||
@@ -61,17 +61,6 @@
|
||||
style="width: 240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="售后类型">
|
||||
<el-select
|
||||
v-model="searchForm.serviceType"
|
||||
placeholder="全部"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
>
|
||||
<el-option label="退款" value="RETURN_MONEY" />
|
||||
<el-option label="退货" value="RETURN_GOODS" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" class="search-btn" @click="handleSearch">搜索</el-button>
|
||||
</el-form-item>
|
||||
@@ -129,13 +118,6 @@
|
||||
{{ $filters.unitPrice(row.applyRefundPrice, "¥") }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="售后类型" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row" :type="serviceTypeTagType(row.serviceType)">
|
||||
{{ serviceTypeText(row.serviceType) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="售后状态" width="180">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row" :type="serviceStatusTagType(row.serviceStatus)">
|
||||
@@ -182,6 +164,7 @@ export default {
|
||||
order: "desc",
|
||||
startDate: "",
|
||||
endDate: "",
|
||||
serviceType: "RETURN_GOODS",
|
||||
orderSn: "",
|
||||
memberName: "",
|
||||
serviceStatus: "",
|
||||
@@ -240,22 +223,6 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
serviceTypeText(type) {
|
||||
const map = {
|
||||
RETURN_MONEY: "退款",
|
||||
RETURN_GOODS: "退货",
|
||||
EXCHANGE_GOODS: "换货",
|
||||
};
|
||||
return map[type] || type || "-";
|
||||
},
|
||||
serviceTypeTagType(type) {
|
||||
const map = {
|
||||
RETURN_MONEY: "primary",
|
||||
RETURN_GOODS: "warning",
|
||||
EXCHANGE_GOODS: "success",
|
||||
};
|
||||
return map[type] || "info";
|
||||
},
|
||||
serviceStatusText(status) {
|
||||
const map = {
|
||||
APPLY: "申请中",
|
||||
@@ -331,7 +298,7 @@ export default {
|
||||
detail(v) {
|
||||
const sn = v.sn;
|
||||
this.$filters.customRouterPush({
|
||||
name: "after-order-detail",
|
||||
name: "return-goods-order-detail",
|
||||
query: { sn: sn },
|
||||
});
|
||||
},
|
||||
|
||||
@@ -1,41 +1,126 @@
|
||||
<template>
|
||||
<div class="search">
|
||||
<el-card>
|
||||
<el-tabs v-model="activeTab" @tab-click="onTabClick">
|
||||
<el-tab-pane label="退款" name="RETURN_MONEY">
|
||||
<div class="operation" style="margin-bottom: 10px">
|
||||
<el-button type="primary" @click="add">添加</el-button>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="取消" name="CANCEL">
|
||||
<div class="operation" style="margin-bottom: 10px">
|
||||
<el-button type="primary" @click="add">添加</el-button>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="退货" name="RETURN_GOODS">
|
||||
<div class="operation" style="margin-bottom: 10px">
|
||||
<el-button type="primary" @click="add">添加</el-button>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="投诉" name="COMPLAIN">
|
||||
<div class="operation" style="margin-bottom: 10px">
|
||||
<el-button type="primary" @click="add">添加</el-button>
|
||||
<el-button @click="getDataList">刷新</el-button>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<el-form
|
||||
ref="searchForm"
|
||||
:model="searchForm"
|
||||
inline
|
||||
label-width="70px"
|
||||
class="search-form"
|
||||
@keyup.enter="handleSearch"
|
||||
>
|
||||
<el-form-item label="关键字" prop="keywords" style="display: block; width: 100%">
|
||||
<el-input
|
||||
v-model="searchForm.keywords"
|
||||
placeholder="请输入商品名称、订单编号搜索"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="订单编号" prop="orderSn">
|
||||
<el-input
|
||||
v-model="searchForm.orderSn"
|
||||
placeholder="请输入订单编号"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="售后单号" prop="sn">
|
||||
<el-input
|
||||
v-model="searchForm.sn"
|
||||
placeholder="请输入售后单号"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="申请时间">
|
||||
<el-date-picker
|
||||
v-model="selectDate"
|
||||
type="datetimerange"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
clearable
|
||||
start-placeholder="开始时间"
|
||||
end-placeholder="结束时间"
|
||||
style="width: 360px"
|
||||
@change="selectDateRange"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="会员名称" prop="memberName">
|
||||
<el-input
|
||||
v-model="searchForm.memberName"
|
||||
placeholder="请输入会员名称"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" class="search-btn" @click="handleSearch">搜索</el-button>
|
||||
<el-button class="search-btn" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-table v-loading="loading" border :data="data" ref="table" style="width: 100%">
|
||||
<el-table-column prop="createBy" label="创建人" min-width="120" />
|
||||
<el-table-column prop="reason" label="原因" min-width="400" />
|
||||
<el-table-column prop="createTime" label="时间" min-width="100" />
|
||||
<el-table-column label="操作" width="200" align="center">
|
||||
<el-card>
|
||||
<div class="order-tab">
|
||||
<el-tabs v-model="currentStatus" @tab-click="onStatusTabClick">
|
||||
<el-tab-pane
|
||||
v-for="item in serviceStatusWithCount"
|
||||
:key="item.value"
|
||||
:label="item.title"
|
||||
:name="item.value"
|
||||
/>
|
||||
</el-tabs>
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
ref="table"
|
||||
v-loading="loading"
|
||||
:data="data"
|
||||
class="mt_10"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-table-column prop="sn" label="售后服务单号" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column prop="orderSn" label="订单编号" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="商品" min-width="300">
|
||||
<template #default="{ row }">
|
||||
<template v-if="row">
|
||||
<a class="link-text" @click="edit(row)">编辑</a>
|
||||
<span class="op-split">|</span>
|
||||
<a class="link-text" @click="remove(row)">删除</a>
|
||||
</template>
|
||||
<div v-if="row" style="margin-top: 5px; height: 80px; display: flex">
|
||||
<div>
|
||||
<img
|
||||
:src="row.goodsImage"
|
||||
style="width: 60px; height: 60px; margin-top: 3px; object-fit: cover; border-radius: 4px"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
<div style="margin-left: 13px">
|
||||
<div class="div-zoom">
|
||||
<a class="link-text" @click="linkTo(row.goodsId, row.skuId)">{{ row.goodsName }}</a>
|
||||
</div>
|
||||
<div style="color: #999; font-size: 12px; margin-top: 5px">
|
||||
商品ID: {{ row.goodsId }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="memberId" label="会员ID" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column prop="memberName" label="会员名称" width="140" />
|
||||
<el-table-column label="售后金额" width="110">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row" :style="{ color: $mainColor }">
|
||||
{{ $filters.unitPrice(row.applyRefundPrice, "¥") }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="售后状态" width="180">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row" :type="serviceStatusTagType(row.serviceStatus)">
|
||||
{{ serviceStatusText(row.serviceStatus) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="申请时间" width="180" />
|
||||
<el-table-column label="操作" fixed="right" align="center" width="100">
|
||||
<template #default="{ row }">
|
||||
<a v-if="row" class="link-text" @click="detail(row)">查看</a>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -53,145 +138,198 @@
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-dialog v-model="modalVisible" :title="modalTitle" width="500px" :close-on-click-modal="false">
|
||||
<el-form ref="form" :model="form" label-width="100px" :rules="formValidate">
|
||||
<el-form-item label="售后原因" prop="reason">
|
||||
<el-input v-model="form.reason" maxlength="20" clearable style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="modalVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="submitLoading" @click="handleSubmit">提交</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as API_Order from "@/api/order";
|
||||
|
||||
const createDefaultSearchForm = () => ({
|
||||
pageNumber: 1,
|
||||
pageSize: 20,
|
||||
sort: "createTime",
|
||||
order: "desc",
|
||||
startDate: "",
|
||||
endDate: "",
|
||||
serviceType: "RETURN_MONEY",
|
||||
orderSn: "",
|
||||
memberName: "",
|
||||
serviceStatus: "",
|
||||
sn: "",
|
||||
keywords: "",
|
||||
});
|
||||
|
||||
export default {
|
||||
name: "returnMoneyOrder",
|
||||
data() {
|
||||
return {
|
||||
activeTab: "RETURN_MONEY",
|
||||
modalVisible: false,
|
||||
modalTitle: "",
|
||||
loading: true,
|
||||
submitLoading: false,
|
||||
form: { reason: "" },
|
||||
formValidate: {
|
||||
reason: [{ required: true, message: "请输入售后原因", trigger: "blur" }],
|
||||
},
|
||||
searchForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 20,
|
||||
sort: "createTime",
|
||||
order: "desc",
|
||||
serviceType: "RETURN_MONEY",
|
||||
},
|
||||
searchForm: createDefaultSearchForm(),
|
||||
selectDate: null,
|
||||
data: [],
|
||||
total: 0,
|
||||
currentStatus: "",
|
||||
afterSaleNumData: {},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
serviceStatusWithCount() {
|
||||
return [
|
||||
{ title: "全部", value: "" },
|
||||
{
|
||||
title: `申请售后${this.afterSaleNumData.applyNum ? "(" + this.afterSaleNumData.applyNum + ")" : ""}`,
|
||||
value: "APPLY",
|
||||
},
|
||||
{
|
||||
title: `通过售后${this.afterSaleNumData.passNum ? "(" + this.afterSaleNumData.passNum + ")" : ""}`,
|
||||
value: "PASS",
|
||||
},
|
||||
{
|
||||
title: `拒绝售后${this.afterSaleNumData.refuseNum ? "(" + this.afterSaleNumData.refuseNum + ")" : ""}`,
|
||||
value: "REFUSE",
|
||||
},
|
||||
{
|
||||
title: `完成售后${this.afterSaleNumData.completeNum ? "(" + this.afterSaleNumData.completeNum + ")" : ""}`,
|
||||
value: "COMPLETE",
|
||||
},
|
||||
{
|
||||
title: `卖家终止售后${this.afterSaleNumData.sellerTerminationNum ? "(" + this.afterSaleNumData.sellerTerminationNum + ")" : ""}`,
|
||||
value: "SELLER_TERMINATION",
|
||||
},
|
||||
{
|
||||
title: `买家取消售后${this.afterSaleNumData.buyerCancelNum ? "(" + this.afterSaleNumData.buyerCancelNum + ")" : ""}`,
|
||||
value: "BUYER_CANCEL",
|
||||
},
|
||||
{
|
||||
title: `等待平台退款${this.afterSaleNumData.waitRefundNum ? "(" + this.afterSaleNumData.waitRefundNum + ")" : ""}`,
|
||||
value: "WAIT_REFUND",
|
||||
},
|
||||
];
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onTabClick(tab) {
|
||||
this.handleClickType(tab.paneName);
|
||||
serviceStatusText(status) {
|
||||
const map = {
|
||||
APPLY: "申请中",
|
||||
PASS: "通过售后",
|
||||
REFUSE: "拒绝售后",
|
||||
BUYER_RETURN: "买家退货,待卖家收货",
|
||||
SELLER_CONFIRM: "卖家确认收货",
|
||||
SELLER_TERMINATION: "卖家终止售后",
|
||||
BUYER_CANCEL: "买家取消售后",
|
||||
COMPLETE: "完成售后",
|
||||
WAIT_REFUND: "待平台退款",
|
||||
};
|
||||
return map[status] || status || "-";
|
||||
},
|
||||
changePage(v) {
|
||||
this.searchForm.pageNumber = v;
|
||||
serviceStatusTagType(status) {
|
||||
const map = {
|
||||
APPLY: "primary",
|
||||
PASS: "info",
|
||||
REFUSE: "warning",
|
||||
BUYER_RETURN: "warning",
|
||||
SELLER_CONFIRM: "",
|
||||
SELLER_TERMINATION: "success",
|
||||
BUYER_CANCEL: "danger",
|
||||
COMPLETE: "success",
|
||||
WAIT_REFUND: "primary",
|
||||
};
|
||||
return map[status] || "info";
|
||||
},
|
||||
init() {
|
||||
this.getDataList();
|
||||
this.getAfterSaleNumData();
|
||||
},
|
||||
changePage() {
|
||||
this.getDataList();
|
||||
},
|
||||
changePageSize(v) {
|
||||
changePageSize() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = v;
|
||||
this.getDataList();
|
||||
},
|
||||
handleClickType(v) {
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.searchForm.pageSize = 20;
|
||||
this.searchForm.serviceType = v;
|
||||
this.getDataList();
|
||||
this.getAfterSaleNumData();
|
||||
},
|
||||
handleReset() {
|
||||
this.searchForm = createDefaultSearchForm();
|
||||
this.selectDate = null;
|
||||
this.currentStatus = "";
|
||||
this.getDataList();
|
||||
this.getAfterSaleNumData();
|
||||
},
|
||||
selectDateRange(v) {
|
||||
if (v) {
|
||||
this.searchForm.startDate = v[0];
|
||||
this.searchForm.endDate = v[1];
|
||||
} else {
|
||||
this.searchForm.startDate = "";
|
||||
this.searchForm.endDate = "";
|
||||
}
|
||||
},
|
||||
getDataList() {
|
||||
this.loading = true;
|
||||
API_Order.getAfterSaleReasonPage(this.searchForm).then((res) => {
|
||||
this.loading = false;
|
||||
if (res.success) {
|
||||
this.data = res.result.records;
|
||||
this.total = res.result.total;
|
||||
}
|
||||
});
|
||||
},
|
||||
add() {
|
||||
this.form.reason = "";
|
||||
this.modalVisible = true;
|
||||
this.modalTitle = "添加售后原因";
|
||||
},
|
||||
edit(v) {
|
||||
this.form.reason = v.reason;
|
||||
this.form.id = v.id;
|
||||
this.modalVisible = true;
|
||||
this.modalTitle = "修改售后原因";
|
||||
},
|
||||
handleSubmit() {
|
||||
this.form.serviceType = this.searchForm.serviceType;
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.submitLoading = true;
|
||||
if (this.modalTitle == "添加售后原因") {
|
||||
delete this.form.id;
|
||||
API_Order.addAfterSaleReason(this.form).then((res) => {
|
||||
this.submitLoading = false;
|
||||
if (res.success) {
|
||||
this.$Message.success("添加成功");
|
||||
this.getDataList();
|
||||
this.modalVisible = false;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
API_Order.editAfterSaleReason(this.form.id, this.form).then((res) => {
|
||||
this.submitLoading = false;
|
||||
if (res.success) {
|
||||
this.$Message.success("修改成功");
|
||||
this.getDataList();
|
||||
this.modalVisible = false;
|
||||
}
|
||||
});
|
||||
API_Order.getAfterSaleOrderPage(this.searchForm)
|
||||
.then((res) => {
|
||||
if (res.success) {
|
||||
this.data = res.result.records;
|
||||
this.total = res.result.total;
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
getAfterSaleNumData() {
|
||||
const { serviceStatus, ...searchParams } = this.searchForm;
|
||||
API_Order.getAfterSaleNumVO(searchParams).then((res) => {
|
||||
if (res.success) {
|
||||
this.afterSaleNumData = res.result;
|
||||
}
|
||||
});
|
||||
},
|
||||
remove(v) {
|
||||
this.$Modal.confirm({
|
||||
title: "确认删除",
|
||||
content: "确认要删除此售后原因?",
|
||||
loading: true,
|
||||
onOk: () => {
|
||||
API_Order.delAfterSaleReason(v.id).then((res) => {
|
||||
this.$Modal.remove();
|
||||
if (res.success) {
|
||||
this.$Message.success("售后原因已删除");
|
||||
this.getDataList();
|
||||
}
|
||||
});
|
||||
},
|
||||
detail(v) {
|
||||
this.$filters.customRouterPush({
|
||||
name: "return-goods-order-detail",
|
||||
query: { sn: v.sn },
|
||||
});
|
||||
},
|
||||
onStatusTabClick(tab) {
|
||||
this.serviceStatusClick(tab.paneName);
|
||||
},
|
||||
serviceStatusClick(item) {
|
||||
this.currentStatus = item;
|
||||
if (item === "" || item === undefined) {
|
||||
delete this.searchForm.serviceStatus;
|
||||
} else {
|
||||
this.searchForm.serviceStatus = item;
|
||||
}
|
||||
this.getDataList();
|
||||
this.getAfterSaleNumData();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getDataList();
|
||||
this.init();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.order-tab {
|
||||
:deep(.el-tabs__item) {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.link-text {
|
||||
color: #2d8cf0;
|
||||
color: #409eff;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
.op-split {
|
||||
display: inline-block;
|
||||
margin: 0 8px;
|
||||
color: #dcdee2;
|
||||
|
||||
.mt_10 {
|
||||
margin-top: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
<div class="main-content">
|
||||
<div class="div-flow-left">
|
||||
<div class="div-form-default">
|
||||
<h3>退货申请</h3>
|
||||
<h3>{{ sectionTitle }}</h3>
|
||||
<dl>
|
||||
<dt>退货商品</dt>
|
||||
<dt>{{ isRefundOnly ? '退款商品' : '退货商品' }}</dt>
|
||||
<dd>
|
||||
<div>
|
||||
<img :src="afterSaleInfo.goodsImage" style="height: 60px">
|
||||
@@ -23,11 +23,11 @@
|
||||
<dd>{{ afterSaleInfo.serviceName }}</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>退货退款编号</dt>
|
||||
<dt>{{ isRefundOnly ? '退款编号' : '退货退款编号' }}</dt>
|
||||
<dd>{{ afterSaleInfo.sn }}</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>退货退款原因</dt>
|
||||
<dt>{{ isRefundOnly ? '退款原因' : '退货退款原因' }}</dt>
|
||||
<dd>{{ afterSaleInfo.reason }}</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
@@ -47,7 +47,7 @@
|
||||
<dd>{{ afterSaleInfo.refundPoint }}</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>退货数量</dt>
|
||||
<dt>{{ isRefundOnly ? '退款数量' : '退货数量' }}</dt>
|
||||
<dd>{{ afterSaleInfo.num }}</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
@@ -92,7 +92,7 @@
|
||||
<priceColorScheme :value="afterSaleInfo.applyRefundPrice" :color="$mainColor"></priceColorScheme>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dl v-if="params.serviceStatus === 'PASS'">
|
||||
<dt>实际退款金额</dt>
|
||||
<dd>
|
||||
<el-input-number :min="0" v-model="params.actualRefundPrice" style="width: 260px" />
|
||||
@@ -264,20 +264,36 @@
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>物流公司</dt>
|
||||
<dd>{{ afterSaleInfo.mlogisticsName }}</dd>
|
||||
<dd>{{ buyerLogisticsName }}</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>物流单号</dt>
|
||||
<dd>
|
||||
{{ afterSaleInfo.mlogisticsNo }}
|
||||
{{ buyerLogisticsNo }}
|
||||
</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>操作</dt>
|
||||
<dd>
|
||||
<el-button
|
||||
v-if="canConfirmReceipt"
|
||||
type="danger"
|
||||
:loading="confirmLoading"
|
||||
@click="sellerConfirmSubmit('PASS')"
|
||||
style="margin-left: 5px"
|
||||
>
|
||||
确认收货
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="canConfirmReceipt"
|
||||
type="primary"
|
||||
plain
|
||||
:loading="confirmLoading"
|
||||
@click="sellerConfirmSubmit('REFUSE')"
|
||||
style="margin-left: 5px"
|
||||
>
|
||||
拒收
|
||||
</el-button>
|
||||
<el-button
|
||||
:loading="submitLoading"
|
||||
@click="logisticsSeller()"
|
||||
style="margin-left: 5px"
|
||||
@@ -302,13 +318,13 @@
|
||||
<dl>
|
||||
<dt>物流公司:</dt>
|
||||
<dd>
|
||||
<div class="text-box">{{ afterSaleInfo.mlogisticsName }}</div>
|
||||
<div class="text-box">{{ buyerLogisticsName }}</div>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>物流单号:</dt>
|
||||
<dd>
|
||||
<div class="text-box">{{ afterSaleInfo.mlogisticsNo }}</div>
|
||||
<div class="text-box">{{ buyerLogisticsNo }}</div>
|
||||
</dd>
|
||||
</dl>
|
||||
<div class="div-express-log">
|
||||
@@ -349,6 +365,7 @@ export default {
|
||||
afterSaleInfo: {}, // 售后信息
|
||||
afterSaleImage: [], //会员申诉图片
|
||||
submitLoading: false, // 添加或编辑提交状态
|
||||
confirmLoading: false, // 确认收货提交状态
|
||||
storeMsg: {}, // 商家地址信息
|
||||
//商家处理意见
|
||||
params: {
|
||||
@@ -359,6 +376,36 @@ export default {
|
||||
refundPriceForm: {
|
||||
remark: "",
|
||||
},
|
||||
afterSaleRefundStatusList: [
|
||||
{
|
||||
name: "退款申请",
|
||||
status: "APPLY",
|
||||
},
|
||||
{
|
||||
name: "通过售后",
|
||||
status: "PASS",
|
||||
},
|
||||
{
|
||||
name: "拒绝售后",
|
||||
status: "REFUSE",
|
||||
},
|
||||
{
|
||||
name: "卖家终止售后",
|
||||
status: "SELLER_TERMINATION",
|
||||
},
|
||||
{
|
||||
name: "买家取消售后",
|
||||
status: "BUYER_CANCEL",
|
||||
},
|
||||
{
|
||||
name: "完成售后",
|
||||
status: "COMPLETE",
|
||||
},
|
||||
{
|
||||
name: "待平台退款",
|
||||
status: "WAIT_REFUND",
|
||||
},
|
||||
],
|
||||
afterSaleStatusList: [
|
||||
// 售后状态列表
|
||||
{
|
||||
@@ -400,6 +447,37 @@ export default {
|
||||
],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isRefundOnly() {
|
||||
return this.afterSaleInfo.serviceType === "RETURN_MONEY";
|
||||
},
|
||||
sectionTitle() {
|
||||
return this.isRefundOnly ? "退款申请" : "退货申请";
|
||||
},
|
||||
buyerLogisticsName() {
|
||||
const info = this.afterSaleInfo;
|
||||
return (
|
||||
info.mLogisticsName ||
|
||||
info.mlogisticsName ||
|
||||
this.logisticsInfo.shipper ||
|
||||
"-"
|
||||
);
|
||||
},
|
||||
buyerLogisticsNo() {
|
||||
const info = this.afterSaleInfo;
|
||||
return (
|
||||
info.mLogisticsNo ||
|
||||
info.mlogisticsNo ||
|
||||
this.logisticsInfo.logisticCode ||
|
||||
"-"
|
||||
);
|
||||
},
|
||||
canConfirmReceipt() {
|
||||
const vo = this.afterSaleInfo.afterSaleAllowOperationVO;
|
||||
if (vo && vo.rog) return true;
|
||||
return this.afterSaleInfo.serviceStatus === "BUYER_RETURN";
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
// 获取售后详情
|
||||
getDetail() {
|
||||
@@ -463,12 +541,39 @@ export default {
|
||||
//查询物流
|
||||
logisticsSeller() {
|
||||
this.logisticsModal = true;
|
||||
this.logisticsInfo = {};
|
||||
API_Order.getAfterSaleTraces(this.sn).then((res) => {
|
||||
if (res.success && res.result != null) {
|
||||
this.logisticsInfo = res.result;
|
||||
}
|
||||
});
|
||||
},
|
||||
// 商家确认收货 / 拒收
|
||||
sellerConfirmSubmit(type) {
|
||||
const isPass = type === "PASS";
|
||||
this.$Modal.confirm({
|
||||
title: isPass ? "确认收货" : "确认拒收",
|
||||
content: isPass ? "请确认已经收到退货货物?" : "确认拒收此货物?",
|
||||
loading: true,
|
||||
onOk: () => {
|
||||
this.confirmLoading = true;
|
||||
API_Order.afterSaleSellerConfirm(this.sn, {
|
||||
serviceStatus: type,
|
||||
remark: this.params.remark || "",
|
||||
}).then((res) => {
|
||||
this.$Modal.remove();
|
||||
this.confirmLoading = false;
|
||||
if (res.success) {
|
||||
this.$Message.success(isPass ? "收货成功" : "拒收成功");
|
||||
this.getDetail();
|
||||
}
|
||||
}).catch(() => {
|
||||
this.$Modal.remove();
|
||||
this.confirmLoading = false;
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
//关闭物流弹出框
|
||||
logisticsClose() {
|
||||
this.logisticsModal = false;
|
||||
@@ -479,7 +584,7 @@ export default {
|
||||
this.$Message.error("请输入备注信息");
|
||||
return;
|
||||
}
|
||||
if (this.params.actualRefundPrice == "") {
|
||||
if (this.params.serviceStatus === "PASS" && this.params.actualRefundPrice === "") {
|
||||
this.$Message.error("请输入退款金额");
|
||||
return;
|
||||
}
|
||||
@@ -493,10 +598,11 @@ export default {
|
||||
});
|
||||
},
|
||||
filterOrderStatus(status) {
|
||||
// 获取订单状态中文
|
||||
const ob = this.afterSaleStatusList.filter((e) => {
|
||||
return e.status === status;
|
||||
});
|
||||
const list =
|
||||
this.afterSaleInfo.serviceType === "RETURN_MONEY"
|
||||
? this.afterSaleRefundStatusList
|
||||
: this.afterSaleStatusList;
|
||||
const ob = list.filter((e) => e.status === status);
|
||||
return ob.length > 0 ? ob[0].name : status;
|
||||
},
|
||||
// 根据订单状态判断是否显示物流信息
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
<el-button v-if="allowOperation.editConsignee" plain type="primary" @click="editAddress">修改收货地址</el-button>
|
||||
<el-button v-if="allowOperation.cancel" plain type="warning" @click="orderCancel">订单取消</el-button>
|
||||
<el-button v-if="orderInfo.order.orderStatus === 'UNPAID'" type="primary" @click="confirmPrice">收款</el-button>
|
||||
<el-button v-if="canOrderTake" type="primary" @click="orderTake">订单核验</el-button>
|
||||
<el-button plain @click="orderLog">订单日志</el-button>
|
||||
<el-button v-if="canPartDelivery" type="primary" @click="openPartDelivery">分包裹发货</el-button>
|
||||
<el-button v-if="$route.query.orderType != 'VIRTUAL'" plain type="primary" style="float:right;" @click="printOrder">打印发货单</el-button>
|
||||
</div>
|
||||
</el-card>
|
||||
@@ -37,6 +39,10 @@
|
||||
{{ orderInfo.order.createTime }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="div-item" v-if="orderInfo.order.verificationCode">
|
||||
<div class="div-item-left">核验码:</div>
|
||||
<div class="div-item-right">{{ orderInfo.order.verificationCode }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="width: 30%; float: left; margin-left: 20px">
|
||||
<div class="div-item" v-if="orderInfo.order.needReceipt == false">
|
||||
@@ -366,6 +372,59 @@
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="partDeliveryModal" title="分包裹发货" width="760px">
|
||||
<el-form ref="partDeliveryForm" :model="partDeliveryForm" label-width="100px" :rules="partDeliveryRules">
|
||||
<el-form-item label="物流公司" prop="logisticsId">
|
||||
<el-select v-model="partDeliveryForm.logisticsId" placeholder="请选择物流公司" filterable style="width: 260px">
|
||||
<el-option
|
||||
v-for="item in checkedLogistics"
|
||||
:key="getLogisticsId(item)"
|
||||
:label="getLogisticsName(item)"
|
||||
:value="getLogisticsId(item)"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="物流单号" prop="logisticsNo">
|
||||
<el-input v-model="partDeliveryForm.logisticsNo" placeholder="请输入物流单号" style="width: 260px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="发货商品" prop="partDeliveryDTOList">
|
||||
<div class="delivery-item-group">
|
||||
<div v-for="item in deliverableOrderItems" :key="getOrderItemId(item)" class="delivery-item">
|
||||
<el-checkbox
|
||||
:model-value="isPartDeliveryItemSelected(item)"
|
||||
@change="(checked) => togglePartDeliveryItem(item, checked)"
|
||||
>
|
||||
<span class="delivery-item-name">{{ item.goodsName }}</span>
|
||||
<span class="delivery-item-num">订单数量 x{{ item.num }}</span>
|
||||
</el-checkbox>
|
||||
<el-input-number
|
||||
v-model="partDeliveryForm.deliveryNumMap[getOrderItemId(item)]"
|
||||
:disabled="!isPartDeliveryItemSelected(item)"
|
||||
:min="1"
|
||||
:max="getMaxDeliveryNum(item)"
|
||||
:precision="0"
|
||||
controls-position="right"
|
||||
size="small"
|
||||
class="delivery-num-input"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!deliverableOrderItems.length" class="delivery-empty">暂无可发货商品</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div v-if="orderPackages.length" class="package-list">
|
||||
<div class="package-title">已有包裹</div>
|
||||
<el-table :data="orderPackages" border size="small">
|
||||
<el-table-column prop="logisticsName" label="物流公司" min-width="120" />
|
||||
<el-table-column prop="logisticsNo" label="物流单号" min-width="160" />
|
||||
</el-table>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="partDeliveryModal = false">关闭</el-button>
|
||||
<el-button type="primary" :loading="partDeliverySubmitting" @click="submitPartDelivery">确认发货</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="printModal" width="530px" @close="printCancel">
|
||||
<template #header>
|
||||
<div style="line-height:26px;height:26px;">
|
||||
@@ -427,12 +486,23 @@
|
||||
</el-dialog>
|
||||
|
||||
|
||||
<el-dialog v-model="orderTakeModal" title="订单核验" width="530px">
|
||||
<el-form ref="orderTakeForm" :model="orderTakeForm" label-width="100px" :rules="orderTakeValidate">
|
||||
<el-form-item label="核验码" prop="qrCode">
|
||||
<el-input v-model="orderTakeForm.qrCode" placeholder="请输入核验码" clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="orderTakeModal = false">取消</el-button>
|
||||
<el-button type="primary" @click="orderTakeSubmit">核验</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<multipleMap ref="map" @callback="selectedRegion" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as API_Logistics from "@/api/logistics";
|
||||
import * as API_Order from "@/api/order";
|
||||
import * as RegExp from "@/libs/RegExp.js";
|
||||
|
||||
@@ -487,6 +557,15 @@ export default {
|
||||
logisticsNo: "", //发货单号
|
||||
logisticsId: "", //物流公司
|
||||
},
|
||||
partDeliveryModal: false,
|
||||
partDeliverySubmitting: false,
|
||||
partDeliveryForm: {
|
||||
logisticsNo: "",
|
||||
logisticsId: "",
|
||||
selectedOrderItemIds: [],
|
||||
deliveryNumMap: {},
|
||||
},
|
||||
orderPackages: [],
|
||||
//验证要调整的订单金额
|
||||
modifyPriceValidate: {
|
||||
reason: [
|
||||
@@ -505,6 +584,13 @@ export default {
|
||||
},
|
||||
addressModal: false, //弹出修改收件信息框
|
||||
printModal: false,
|
||||
orderTakeModal: false,
|
||||
orderTakeForm: {
|
||||
qrCode: "",
|
||||
},
|
||||
orderTakeValidate: {
|
||||
qrCode: [{ required: true, message: "核验码不能为空", trigger: "blur" }],
|
||||
},
|
||||
//收件地址表单
|
||||
addressForm: {
|
||||
consigneeName: "",
|
||||
@@ -517,6 +603,10 @@ export default {
|
||||
logisticsNo: [{ required: true, message: "发货单号不能为空", trigger: "change" }],
|
||||
logisticsId: [{ required: true, message: "请选择物流公司", trigger: "blur" }],
|
||||
},
|
||||
partDeliveryRules: {
|
||||
logisticsNo: [{ required: true, message: "发货单号不能为空", trigger: "change" }],
|
||||
logisticsId: [{ required: true, message: "请选择物流公司", trigger: "change" }],
|
||||
},
|
||||
addressRule: {
|
||||
consigneeName: [
|
||||
{ required: true, message: "收货人姓名不能为空", trigger: "blur" },
|
||||
@@ -537,6 +627,28 @@ export default {
|
||||
data: [], // 表单数据
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
canPartDelivery() {
|
||||
const status = this.orderInfo.order && this.orderInfo.order.orderStatus;
|
||||
return (
|
||||
this.$route.query.orderType !== "VIRTUAL" &&
|
||||
["UNDELIVERED", "PARTS_DELIVERED"].includes(status) &&
|
||||
this.deliverableOrderItems.length > 0
|
||||
);
|
||||
},
|
||||
deliverableOrderItems() {
|
||||
return (this.data || []).filter((item) => this.getOrderItemId(item));
|
||||
},
|
||||
canOrderTake() {
|
||||
if (this.allowOperation.take) return true;
|
||||
const order = this.orderInfo?.order;
|
||||
if (!order) return false;
|
||||
const isVirtual =
|
||||
this.$route.query.orderType === "VIRTUAL" ||
|
||||
order.orderType === "VIRTUAL";
|
||||
return isVirtual && order.orderStatus === "TAKE";
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
$route (to, from) {
|
||||
this.$router.go(0);
|
||||
@@ -558,6 +670,106 @@ export default {
|
||||
gotoHomes () {
|
||||
return false
|
||||
},
|
||||
getOrderItemId(item) {
|
||||
return item && (item.id || item.orderItemId || item.sn);
|
||||
},
|
||||
getLogisticsId(item) {
|
||||
return item && (item.logisticsId || item.id);
|
||||
},
|
||||
getLogisticsName(item) {
|
||||
return item && (item.logisticsName || item.name || item.logisticsCompany || item.logisticsId || item.id);
|
||||
},
|
||||
getMaxDeliveryNum(item) {
|
||||
const num = Number(item && item.num);
|
||||
return Number.isFinite(num) && num > 0 ? num : 999999;
|
||||
},
|
||||
isPartDeliveryItemSelected(item) {
|
||||
const id = this.getOrderItemId(item);
|
||||
return !!id && this.partDeliveryForm.selectedOrderItemIds.includes(id);
|
||||
},
|
||||
togglePartDeliveryItem(item, checked) {
|
||||
const id = this.getOrderItemId(item);
|
||||
if (!id) return;
|
||||
if (checked) {
|
||||
if (!this.partDeliveryForm.selectedOrderItemIds.includes(id)) {
|
||||
this.partDeliveryForm.selectedOrderItemIds.push(id);
|
||||
}
|
||||
if (!this.partDeliveryForm.deliveryNumMap[id]) {
|
||||
this.partDeliveryForm.deliveryNumMap[id] = this.getMaxDeliveryNum(item);
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.partDeliveryForm.selectedOrderItemIds = this.partDeliveryForm.selectedOrderItemIds.filter((itemId) => itemId !== id);
|
||||
delete this.partDeliveryForm.deliveryNumMap[id];
|
||||
},
|
||||
buildPartDeliveryDTOList() {
|
||||
return this.partDeliveryForm.selectedOrderItemIds
|
||||
.map((orderItemId) => ({
|
||||
orderItemId,
|
||||
deliveryNum: Number(this.partDeliveryForm.deliveryNumMap[orderItemId]),
|
||||
}))
|
||||
.filter((item) => item.orderItemId && item.deliveryNum > 0);
|
||||
},
|
||||
resetPartDeliveryForm() {
|
||||
this.partDeliveryForm = {
|
||||
logisticsNo: "",
|
||||
logisticsId: "",
|
||||
selectedOrderItemIds: [],
|
||||
deliveryNumMap: {},
|
||||
};
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.partDeliveryForm) {
|
||||
this.$refs.partDeliveryForm.clearValidate();
|
||||
}
|
||||
});
|
||||
},
|
||||
openPartDelivery() {
|
||||
this.resetPartDeliveryForm();
|
||||
this.partDeliveryModal = true;
|
||||
this.getCheckedLogistics();
|
||||
this.getOrderPackages();
|
||||
},
|
||||
getCheckedLogistics() {
|
||||
API_Order.getLogisticsChecked().then((res) => {
|
||||
if (res.success) {
|
||||
this.checkedLogistics = Array.isArray(res.result) ? res.result : [];
|
||||
}
|
||||
});
|
||||
},
|
||||
getOrderPackages() {
|
||||
API_Order.getPackage(this.sn).then((res) => {
|
||||
if (res.success) {
|
||||
this.orderPackages = Array.isArray(res.result) ? res.result : [];
|
||||
}
|
||||
});
|
||||
},
|
||||
submitPartDelivery() {
|
||||
this.$refs.partDeliveryForm.validate((valid) => {
|
||||
if (!valid) return;
|
||||
const partDeliveryDTOList = this.buildPartDeliveryDTOList();
|
||||
if (!partDeliveryDTOList.length) {
|
||||
this.$Message.error("请选择本次发货商品并填写发货数量");
|
||||
return;
|
||||
}
|
||||
this.partDeliverySubmitting = true;
|
||||
API_Order.partDelivery(this.sn, {
|
||||
orderSn: this.sn,
|
||||
logisticsNo: this.partDeliveryForm.logisticsNo,
|
||||
logisticsId: this.partDeliveryForm.logisticsId,
|
||||
partDeliveryDTOList,
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.success) {
|
||||
this.$Message.success("发货成功");
|
||||
this.partDeliveryModal = false;
|
||||
this.getDataList();
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.partDeliverySubmitting = false;
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
//确认收款
|
||||
confirmPrice () {
|
||||
@@ -602,7 +814,7 @@ export default {
|
||||
// 获取订单详情
|
||||
getDataList () {
|
||||
this.loading = true;
|
||||
API_Order.orderDetail(this.sn).then((res) => {
|
||||
API_Order.getOrderDetail(this.sn).then((res) => {
|
||||
this.loading = false;
|
||||
if (res.success) {
|
||||
this.orderInfo = res.result;
|
||||
@@ -623,7 +835,7 @@ export default {
|
||||
modifyPriceSubmit () {
|
||||
this.$refs.modifyPriceForm.validate((valid) => {
|
||||
if (valid) {
|
||||
API_Order.updateOrderPrice(this.sn, this.modifyPriceForm).then((res) => {
|
||||
API_Order.modifyOrderPrice(this.sn, this.modifyPriceForm).then((res) => {
|
||||
if (res.success) {
|
||||
this.$Message.success("修改订单金额成功");
|
||||
this.modal = false;
|
||||
@@ -655,7 +867,7 @@ export default {
|
||||
orderCancelSubmit () {
|
||||
this.$refs.orderCancelForm.validate((valid) => {
|
||||
if (valid) {
|
||||
API_Order.orderCancel(this.sn, this.orderCancelForm).then((res) => {
|
||||
API_Order.cancelOrder(this.sn, this.orderCancelForm).then((res) => {
|
||||
if (res.success) {
|
||||
this.$Message.success("取消成功");
|
||||
this.getDataList();
|
||||
@@ -673,6 +885,25 @@ export default {
|
||||
handelCancel () {
|
||||
this.orderLogModal = false;
|
||||
},
|
||||
orderTake() {
|
||||
this.orderTakeForm.qrCode = this.orderInfo.order.verificationCode || "";
|
||||
this.orderTakeModal = true;
|
||||
this.$nextTick(() => {
|
||||
this.$refs.orderTakeForm?.clearValidate();
|
||||
});
|
||||
},
|
||||
orderTakeSubmit() {
|
||||
this.$refs.orderTakeForm.validate((valid) => {
|
||||
if (!valid) return;
|
||||
API_Order.orderTake(this.sn, this.orderTakeForm.qrCode).then((res) => {
|
||||
if (res.success) {
|
||||
this.$Message.success("订单核验成功");
|
||||
this.orderTakeModal = false;
|
||||
this.getDataList();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
//打印发货单
|
||||
printOrder () {
|
||||
this.printModal = true;
|
||||
@@ -734,6 +965,54 @@ export default {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.delivery-item-group {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.delivery-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
margin: 0 0 8px 0;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.delivery-item-name {
|
||||
display: inline-block;
|
||||
max-width: 420px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
vertical-align: middle;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.delivery-item-num {
|
||||
margin-left: 12px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.delivery-num-input {
|
||||
width: 120px;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.delivery-empty {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.package-list {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.package-title {
|
||||
margin-bottom: 8px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.flex-card {
|
||||
display: flex;
|
||||
height: 600px;
|
||||
|
||||
Reference in New Issue
Block a user