feat:【mall 商城】售后退款(100% antd detail)

This commit is contained in:
YunaiV
2025-10-14 19:46:15 +08:00
parent b512bcc134
commit 9f3a0a9f34
4 changed files with 113 additions and 119 deletions

View File

@@ -107,26 +107,26 @@ export function getAfterSale(id: number) {
} }
/** 同意售后 */ /** 同意售后 */
export function agree(id: number) { export function agreeAfterSale(id: number) {
return requestClient.put(`/trade/after-sale/agree?id=${id}`); return requestClient.put(`/trade/after-sale/agree?id=${id}`);
} }
/** 拒绝售后 */ /** 拒绝售后 */
export function disagree(data: MallAfterSaleApi.DisagreeRequest) { export function disagreeAfterSale(data: MallAfterSaleApi.DisagreeRequest) {
return requestClient.put('/trade/after-sale/disagree', data); return requestClient.put('/trade/after-sale/disagree', data);
} }
/** 确认收货 */ /** 确认收货 */
export function receive(id: number) { export function receiveAfterSale(id: number) {
return requestClient.put(`/trade/after-sale/receive?id=${id}`); return requestClient.put(`/trade/after-sale/receive?id=${id}`);
} }
/** 拒绝收货 */ /** 拒绝收货 */
export function refuse(id: number) { export function refuseAfterSale(id: number) {
return requestClient.put(`/trade/after-sale/refuse?id=${id}`); return requestClient.put(`/trade/after-sale/refuse?id=${id}`);
} }
/** 确认退款 */ /** 确认退款 */
export function refund(id: number) { export function refundAfterSale(id: number) {
return requestClient.put(`/trade/after-sale/refund?id=${id}`); return requestClient.put(`/trade/after-sale/refund?id=${id}`);
} }

View File

@@ -6,16 +6,21 @@ import type { MallOrderApi } from '#/api/mall/trade/order';
import { onMounted, ref } from 'vue'; import { onMounted, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import { Page, useVbenModal } from '@vben/common-ui'; import { confirm, Page, useVbenModal } from '@vben/common-ui';
import { DICT_TYPE } from '@vben/constants'; import { DICT_TYPE } from '@vben/constants';
import { useTabs } from '@vben/hooks'; import { useTabs } from '@vben/hooks';
import { $t } from '@vben/locales'; import { $t } from '@vben/locales';
import { Card, message, Modal, Tag } from 'ant-design-vue'; import { Card, message, Tag } from 'ant-design-vue';
import { useVbenVxeGrid } from '#/adapter/vxe-table'; import { useVbenVxeGrid } from '#/adapter/vxe-table';
// TODO @AI移除 AfterSaleApi直接换成 api import {
import * as AfterSaleApi from '#/api/mall/trade/afterSale/index'; agreeAfterSale,
getAfterSale,
receiveAfterSale,
refundAfterSale,
refuseAfterSale,
} from '#/api/mall/trade/afterSale';
import { useDescription } from '#/components/description'; import { useDescription } from '#/components/description';
import { DictTag } from '#/components/dict-tag'; import { DictTag } from '#/components/dict-tag';
import { TableAction } from '#/components/table-action'; import { TableAction } from '#/components/table-action';
@@ -112,15 +117,15 @@ const [DisagreeModal, disagreeModalApi] = useVbenModal({
async function getDetail() { async function getDetail() {
loading.value = true; loading.value = true;
try { try {
const res = await AfterSaleApi.getAfterSale(afterSaleId.value); const res = await getAfterSale(afterSaleId.value);
if (res === null) { if (res === null) {
message.error('售后订单不存在'); message.error('售后订单不存在');
handleBack(); handleBack();
return; return;
} }
afterSale.value = res; afterSale.value = res;
await productGridApi.setGridOptions({ data: [afterSale.value.orderItem] }); productGridApi.setGridOptions({ data: [afterSale.value.orderItem] });
await operateLogGridApi.setGridOptions({ operateLogGridApi.setGridOptions({
data: afterSale.value.logs || [], data: afterSale.value.logs || [],
}); });
} finally { } finally {
@@ -129,64 +134,72 @@ async function getDetail() {
} }
/** 同意售后 */ /** 同意售后 */
// TODO @AI需要 loading async function handleAgree() {
async function agree() { await confirm('是否同意售后?');
Modal.confirm({ const hideLoading = message.loading({
title: '确认操作', content: '正在处理中...',
content: '是否同意售后?', duration: 0,
onOk: async () => {
await AfterSaleApi.agree(afterSale.value.id!);
message.success($t('page.common.success'));
await getDetail();
},
}); });
try {
await agreeAfterSale(afterSale.value.id!);
message.success($t('ui.actionMessage.operationSuccess'));
await getDetail();
} finally {
hideLoading();
}
} }
/** 拒绝售后 */ /** 拒绝售后 */
function disagree() { function handleDisagree() {
disagreeModalApi.setData({ afterSale: afterSale.value }).open(); disagreeModalApi.setData({ afterSale: afterSale.value }).open();
} }
/** 确认收货 */ /** 确认收货 */
// TODO @AI需要 loading async function handleReceive() {
async function receive() { await confirm('是否确认收货?');
Modal.confirm({ const hideLoading = message.loading({
title: '确认操作', content: '正在处理中...',
content: '是否确认收货?', duration: 0,
onOk: async () => {
await AfterSaleApi.receive(afterSale.value.id!);
message.success($t('page.common.success'));
await getDetail();
},
}); });
try {
await receiveAfterSale(afterSale.value.id!);
message.success($t('ui.actionMessage.operationSuccess'));
await getDetail();
} finally {
hideLoading();
}
} }
/** 拒绝收货 */ /** 拒绝收货 */
// TODO @AI需要 loading async function handleRefuse() {
async function refuse() { await confirm('是否拒绝收货?');
Modal.confirm({ const hideLoading = message.loading({
title: '确认操作', content: '正在处理中...',
content: '是否拒绝收货?', duration: 0,
onOk: async () => {
await AfterSaleApi.refuse(afterSale.value.id!);
message.success($t('page.common.success'));
await getDetail();
},
}); });
try {
await refuseAfterSale(afterSale.value.id!);
message.success($t('ui.actionMessage.operationSuccess'));
await getDetail();
} finally {
hideLoading();
}
} }
/** 确认退款 */ /** 确认退款 */
// TODO @AI需要 loading async function handleRefund() {
async function refund() { await confirm('是否确认退款?');
Modal.confirm({ const hideLoading = message.loading({
title: '确认操作', content: '正在处理中...',
content: '是否确认退款?', duration: 0,
onOk: async () => {
await AfterSaleApi.refund(afterSale.value.id!);
message.success($t('page.common.success'));
await getDetail();
},
}); });
try {
await refundAfterSale(afterSale.value.id!);
message.success($t('ui.actionMessage.operationSuccess'));
await getDetail();
} finally {
hideLoading();
}
} }
/** 返回列表页 */ /** 返回列表页 */
@@ -195,66 +208,7 @@ function handleBack() {
router.push('/mall/trade/afterSale'); router.push('/mall/trade/afterSale');
} }
/** 获取操作按钮 */ /** 初始化 */
function getActionButtons() {
const buttons: any[] = [
{
label: '返回',
type: 'default',
icon: 'lucide:arrow-left',
onClick: handleBack,
},
];
// 根据状态添加不同的操作按钮
switch (afterSale.value.status) {
case 10: {
buttons.push(
{
label: '同意售后',
type: 'primary',
onClick: agree,
},
{
label: '拒绝售后',
type: 'primary',
onClick: disagree,
},
);
break;
}
case 30: {
buttons.push(
{
label: '确认收货',
type: 'primary',
onClick: receive,
},
{
label: '拒绝收货',
type: 'primary',
onClick: refuse,
},
);
break;
}
case 40: {
buttons.push({
label: '确认退款',
type: 'primary',
onClick: refund,
});
break;
}
// No default
}
return buttons;
}
onMounted(() => { onMounted(() => {
afterSaleId.value = Number(route.params.id); afterSaleId.value = Number(route.params.id);
getDetail(); getDetail();
@@ -267,9 +221,49 @@ onMounted(() => {
<DisagreeModal @success="getDetail" /> <DisagreeModal @success="getDetail" />
--> -->
<!-- TODO @AI直接写不用 getActionButtons按钮是否展示使用 ifShow -->
<template #extra> <template #extra>
<TableAction :actions="getActionButtons()" /> <TableAction
:actions="[
{
label: '返回',
type: 'default',
icon: 'lucide:arrow-left',
onClick: handleBack,
},
{
label: '同意售后',
type: 'primary',
onClick: handleAgree,
ifShow: afterSale.status === 10,
},
{
label: '拒绝售后',
type: 'primary',
danger: true,
onClick: handleDisagree,
// ifShow: afterSale.status === 10,
},
{
label: '确认收货',
type: 'primary',
onClick: handleReceive,
ifShow: afterSale.status === 30,
},
{
label: '拒绝收货',
type: 'primary',
danger: true,
onClick: handleRefuse,
ifShow: afterSale.status === 30,
},
{
label: '确认退款',
type: 'primary',
onClick: handleRefund,
ifShow: afterSale.status === 40,
},
]"
/>
</template> </template>
<!-- 订单信息 --> <!-- 订单信息 -->

View File

@@ -212,7 +212,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
<SummaryCard <SummaryCard
class="flex flex-1" class="flex flex-1"
title="退款单数" title="退款单数"
icon="heroicons:receipt-refund" icon="heroicons:receipt-refundAfterSale"
icon-color="bg-yellow-100" icon-color="bg-yellow-100"
icon-bg-color="text-yellow-500" icon-bg-color="text-yellow-500"
:value="summary?.afterSaleCount || 0" :value="summary?.afterSaleCount || 0"
@@ -220,7 +220,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
<SummaryCard <SummaryCard
class="flex flex-1" class="flex flex-1"
title="退款金额" title="退款金额"
icon="ri:refund-2-line" icon="ri:refundAfterSale-2-line"
icon-color="bg-green-100" icon-color="bg-green-100"
icon-bg-color="text-green-500" icon-bg-color="text-green-500"
prefix="¥" prefix="¥"

View File

@@ -218,7 +218,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
<SummaryCard <SummaryCard
class="flex flex-1" class="flex flex-1"
title="退款单数" title="退款单数"
icon="heroicons:receipt-refund" icon="heroicons:receipt-refundAfterSale"
icon-color="bg-yellow-100" icon-color="bg-yellow-100"
icon-bg-color="text-yellow-500" icon-bg-color="text-yellow-500"
:value="summary?.afterSaleCount || 0" :value="summary?.afterSaleCount || 0"
@@ -226,7 +226,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
<SummaryCard <SummaryCard
class="flex flex-1" class="flex flex-1"
title="退款金额" title="退款金额"
icon="ri:refund-2-line" icon="ri:refundAfterSale-2-line"
icon-color="bg-green-100" icon-color="bg-green-100"
icon-bg-color="text-green-500" icon-bg-color="text-green-500"
prefix="¥" prefix="¥"