| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- <script setup lang="tsx">
- import { reactive, ref, unref, useTemplateRef, watch } from 'vue';
- import { NImage, NTag } from 'naive-ui';
- import { fetchGetAfterSalesOrderList, fetchGetAfterSalesStatusNum } from '@/service/api/delivery/after-sales-order';
- import { useAppStore } from '@/store/modules/app';
- import { defaultTransform, useNaivePaginatedTable } from '@/hooks/common/table';
- import { copyTextToClipboard } from '@/utils/zt';
- import { $t } from '@/locales';
- import { useForm } from '@/components/zt/Form/hooks/useForm';
- import NormalMoadl from '../normal-order/component/normal-modal.vue';
- import { SearchForm, orderStatus } from '../normal-order/normal-order';
- import { refundEnum, refundStatus } from './after-sales-order';
- const appStore = useAppStore();
- const checkedRowKeys = ref([]);
- const activeTab = ref(0);
- const statusList = ref<{ label: string; value: number; num?: number; key: string }[]>([]);
- const orderMoadl = useTemplateRef('orderMoadl');
- const [registerSearchForm, { getFieldsValue }] = useForm({
- schemas: SearchForm,
- showAdvancedButton: false,
- labelWidth: 120,
- layout: 'horizontal',
- gridProps: {
- cols: '1 xl:4 s:1 l:3',
- itemResponsive: true
- },
- collapsedRows: 1
- });
- const searchForm = ref();
- const searchParams = reactive({
- current: 1,
- size: 10
- });
- const { columns, data, loading, getData, mobilePagination } = useNaivePaginatedTable({
- api: () => fetchGetAfterSalesOrderList({ ...searchParams, returnMoneySts: activeTab.value, ...unref(searchForm) }),
- transform: response => defaultTransform(response),
- paginationProps: {
- pageSizes: [10, 20, 50, 100, 150, 200]
- },
- onPaginationParamsChange: params => {
- searchParams.current = Number(params.page);
- searchParams.size = Number(params.pageSize);
- },
- columns: () => [
- {
- key: 'orderItems',
- title: '商品',
- align: 'left',
- width: 200,
- colSpan: (_rowData, _rowIndex) => 2,
- render: row => {
- return (
- <div>
- <div class={'mb3 flex items-center'}>
- <n-tag>
- <div class={'flex items-center'}>
- 退款编号:{row.refundSn}
- <div onClick={() => handleCopy(row.refundSn)}>
- <svgIcon icon={'bxs:copy'} class={'mx-3 cursor-pointer text-[#f97316]'}></svgIcon>
- </div>
- 订单编号:{row.orderNumber}
- <div onClick={() => handleCopy(row.orderNumber)}>
- <svgIcon icon={'bxs:copy'} class={'mx-3 cursor-pointer text-[#f97316]'}></svgIcon>
- </div>
- 申请时间:
- {row.applyTime} 门店名称 {row.shopName}
- </div>
- </n-tag>
- </div>
- {row.orderRefundSkuList?.map(item => {
- return (
- <div class={'mb-3 h-80px flex items-center'}>
- <NImage src={item.pic} class="h-[80px] min-w-80px w-[80px]" lazy />
- <div class={'ml12px flex-1'}>
- <div class={'w-full flex items-center justify-between'}>
- <div class={'w200px'}>
- <n-ellipsis class={'w250px'}>
- <span class={'w-full text-left text-15px font-semibold'}>{item.skuName}</span>
- </n-ellipsis>
- </div>
- <div class={'w150px pl30px text-left'}>
- <div class={'text-16px font-semibold'}>¥{item.skuPrice} </div>
- </div>
- </div>
- <div class={'w-full flex items-center justify-between'}>
- <div class={'w200px text-gray'}>规格:{item.spec || '--'} </div>
- <div class={'w150px pl30px text-left text-gray'}>x{item.productCount} </div>
- </div>
- </div>
- </div>
- );
- })}
- </div>
- );
- }
- },
- {
- key: 'deptName',
- title: '单价(元)/数量',
- align: 'center',
- width: 100
- },
- {
- key: 'actualTotal',
- title: '实付金额(元)',
- align: 'center',
- width: 120,
- render: row => {
- return (
- <div class={'mt7'}>
- <div class={'text-16px text-#ff0000 font-semibold'}>{row.actualTotal} 元</div>
- <div>共 {row.goodsTotalCount} 件</div>
- </div>
- );
- }
- },
- {
- key: 'refundAmount',
- title: '退款金额',
- align: 'center',
- width: 120,
- render: row => {
- return (
- <div class={'mt7'}>
- <div class={'text-16px text-#ff0000 font-semibold'}>{row.actualTotal} 元</div>
- <div>共 {row.goodsTotalCount} 件</div>
- </div>
- );
- }
- },
- {
- title: '商品状况',
- key: 'goods',
- width: 220,
- align: 'center',
- render: row => {
- const TypeText = ['仅退款', '退款退货', '差价退款'];
- return (
- <div class={'mt7'}>
- <div class={'text-16px font-semibold'}>{TypeText[Number(row.applyType) - 1] || '未知状况'} </div>
- <div class={'text-#ff0000'}> {row.buyerReason} </div>
- </div>
- );
- }
- },
- {
- key: 'status',
- title: '订单状态',
- align: 'center',
- width: 220,
- render: row => {
- const statusKey = row.hbOrderStatus as keyof typeof orderStatus;
- const statusText = orderStatus[statusKey] || '未知状态';
- return <NTag class={'mt7'}>{statusText}</NTag>;
- }
- },
- {
- key: 'createTime',
- title: '售后状态',
- align: 'center',
- width: 160,
- render: row => {
- const statusKey = row.returnMoneySts as keyof typeof refundStatus;
- const statusText = refundStatus[statusKey] || '暂无售后';
- return <NTag class={'mt7'}>{statusText}</NTag>;
- }
- },
- {
- key: 'operate',
- title: $t('common.operate'),
- align: 'center',
- width: 130,
- fixed: 'right',
- render: row => {
- return (
- <div class={'mt7'}>
- <n-button size="small" type="primary" quaternary onClick={() => handleOpenMoadl(row)}>
- 查看订单
- </n-button>
- </div>
- );
- }
- }
- ]
- });
- function handleOpenMoadl(row: Api.delivery.OrderRefund) {
- if (!row.orderNumber) {
- window.$message?.error('订单异常');
- return;
- }
- orderMoadl.value?.open(String(row.orderNumber));
- }
- async function getNums() {
- const { data: keyData } = await fetchGetAfterSalesStatusNum({ ...getFieldsValue() });
- if (!keyData) return;
- const orderStatusList = [
- {
- label: '全部',
- value: 0,
- key: 'allCount'
- },
- {
- label: '买家申请',
- value: refundEnum.BUYER_APPLY,
- key: 'sellerApplyCount'
- },
- {
- label: '卖家拒绝',
- value: refundEnum.SELLER_REFUSE,
- key: 'sellerAcceptCount'
- },
- {
- label: '买家发货',
- value: refundEnum.BUYER_DELIVERY,
- key: 'sellerAcceptCount'
- },
- {
- label: '卖家接受',
- value: refundEnum.SELLER_AGREE,
- key: 'buyerDeliveryCount'
- },
- {
- label: '退款成功',
- value: refundEnum.REFUND_SUCCESS,
- key: 'refundCompleteCount'
- },
- {
- label: '撤回申请',
- value: refundEnum.REVOKE_APPLY,
- key: 'withdrawApplyCount'
- }
- ];
- const updatedOrderStatusList = orderStatusList.map(item => {
- if (Object.hasOwn(keyData, item.key)) {
- return {
- ...item,
- num: keyData[item.key]
- };
- }
- return item;
- });
- statusList.value = updatedOrderStatusList;
- }
- getNums();
- watch(
- () => [activeTab.value],
- () => {
- searchParams.current = 1;
- getData();
- }
- );
- function handleSearch() {
- const form = getFieldsValue();
- if (form.createTime) {
- form.startTime = form.createTime[0];
- form.endTime = form.createTime[1];
- delete form.createTime;
- }
- searchForm.value = form;
- getData();
- getNums();
- }
- function handleReset() {
- searchForm.value = getFieldsValue();
- getData();
- }
- async function handleCopy(No: string) {
- await copyTextToClipboard(No);
- }
- </script>
- <template>
- <div class="flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
- <NCard :bordered="false" size="small">
- <NCollapse display-directive="show">
- <NCollapseItem title="搜索">
- <BasicForm @register-form="registerSearchForm" @submit="handleSearch" @reset="handleReset" />
- </NCollapseItem>
- </NCollapse>
- </NCard>
- <NCard title="售后列表" :bordered="false" size="small" class="card-wrapper sm:flex-1-hidden">
- <NTabs v-model:value="activeTab" type="line" animated class="mb-16px h-full">
- <NTabPane
- v-for="item in statusList"
- :key="item.value"
- display-directive="show"
- :name="item.value"
- :tab="`${item.label}(${item.num})`"
- >
- <NDataTable
- v-model:checked-row-keys="checkedRowKeys"
- :columns="columns"
- :data="data"
- size="small"
- :flex-height="!appStore.isMobile"
- :scroll-x="1800"
- :loading="loading"
- :row-key="row => row.refundId"
- remote
- class="sm:h-full"
- :pagination="mobilePagination"
- />
- </NTabPane>
- </NTabs>
- <NormalMoadl ref="orderMoadl" @finish="(getData, getNums)"></NormalMoadl>
- </NCard>
- </div>
- </template>
- <style scoped lang="scss">
- :deep(.n-tabs-pane-wrapper) {
- height: 100%;
- }
- :deep(.n-tab-pane) {
- height: 100%;
- }
- </style>
|