shop-front-end/src/views/shop/approval/index.vue

305 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import { ref } from "vue";
import { PureTableBar } from "@/components/RePureTableBar";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import { getReturnApprovalListApi, deleteReturnApprovalApi, exportReturnApprovalExcelApi, ReturnApprovalDTO, SearchReturnApprovalQuery } from "@/api/shop/approval";
import Delete from "@iconify-icons/ep/delete";
import Search from "@iconify-icons/ep/search";
import Refresh from "@iconify-icons/ep/refresh";
import View from "@iconify-icons/ep/view";
import { ElMessage, ElMessageBox } from "element-plus";
defineOptions({
name: "Approval"
});
const formRef = ref();
const tableRef = ref();
// 搜索表单
const searchFormParams = ref<SearchReturnApprovalQuery>({
approvalId: null,
orderId: null,
goodsId: null,
status: null,
approvalTime: null,
paymentMethod: null
});
// 分页参数
const pagination = ref({
pageSize: 10,
currentPage: 1,
total: 0
});
const loading = ref(false);
const exportLoading = ref(false);
const dataList = ref<ReturnApprovalDTO[]>([]);
const multipleSelection = ref<number[]>([]);
const detailVisible = ref(false);
const currentDetail = ref<ReturnApprovalDTO>();
// 获取审批列表
const getList = async () => {
try {
loading.value = true;
const { data } = await getReturnApprovalListApi({
...searchFormParams.value,
pageSize: pagination.value.pageSize,
pageNum: pagination.value.currentPage
});
dataList.value = data.rows.map(item => ({
...item,
statusStr: { 1: '待审核', 2: '已通过', 3: '已驳回' }[item.status],
auditImages: item.status === 2 ? item.auditImages : ''
}));
pagination.value.total = data.total;
} finally {
loading.value = false;
}
};
// 搜索
const onSearch = () => {
pagination.value.currentPage = 1;
getList();
};
// 重置
const resetForm = () => {
formRef.value.resetFields();
onSearch();
};
// 分页变化
const handlePaginationChange = () => getList();
// 批量删除
const handleExport = async () => {
try {
exportLoading.value = true;
const dateSuffix = searchFormParams.value.approvalTime
? `_${searchFormParams.value.approvalTime.split(' ')[0].replace(/-/g, '')}`
: '';
const fileName = `退货审批列表${dateSuffix}.xlsx`;
await exportReturnApprovalExcelApi({
...searchFormParams.value,
pageSize: pagination.value.pageSize,
pageNum: pagination.value.currentPage
}, fileName);
ElMessage.success('导出任务已开始,请稍后查看下载文件');
} catch (e) {
ElMessage.error('导出失败');
} finally {
exportLoading.value = false;
}
};
const handleBulkDelete = async () => {
if (multipleSelection.value.length === 0) return;
try {
await ElMessageBox.confirm(
`确认删除选中的${multipleSelection.value.length}项审批记录?`,
"警告",
{ confirmButtonText: "确定", cancelButtonText: "取消", type: "warning" }
);
await deleteReturnApprovalApi(multipleSelection.value);
ElMessage.success("批量删除成功");
multipleSelection.value = [];
getList();
} catch (error) {
console.error("删除取消或失败", error);
}
};
// 查看详情
const showDetail = (row: ReturnApprovalDTO) => {
currentDetail.value = row;
detailVisible.value = true;
};
getList();
</script>
<template>
<div class="main">
<el-form ref="formRef" :inline="true" :model="searchFormParams"
class="search-form bg-bg_color flex w-[99/100] pl-[22px] pt-[12px]">
<el-form-item>
<el-date-picker v-model="searchFormParams.approvalTime" type="date" placeholder="选择审批时间"
value-format="YYYY-MM-DD HH:mm:ss" class="!w-[200px]" />
</el-form-item>
<el-form-item prop="approvalId">
<el-input @keydown.enter.prevent="onSearch" v-model.number="searchFormParams.approvalId" placeholder="请输入审批ID"
clearable class="!w-[180px]" />
</el-form-item>
<el-form-item prop="orderId">
<el-input @keydown.enter.prevent="onSearch" v-model.number="searchFormParams.orderId" placeholder="请输入订单ID"
clearable class="!w-[180px]" />
</el-form-item>
<el-form-item prop="goodsId">
<el-input @keydown.enter.prevent="onSearch" v-model.number="searchFormParams.goodsId" placeholder="请输入商品ID"
clearable class="!w-[180px]" />
</el-form-item>
<el-form-item prop="status">
<el-select v-model="searchFormParams.status" placeholder="请选择审核状态" clearable class="!w-[180px]">
<el-option label="待审核" :value="1" />
<el-option label="已通过" :value="2" />
<el-option label="已驳回" :value="3" />
</el-select>
</el-form-item>
<el-form-item prop="paymentMethod">
<el-select v-model="searchFormParams.paymentMethod" placeholder="请选择支付方式" clearable class="!w-[180px]">
<el-option label="微信支付" value="wechat" />
<el-option label="余额支付" value="balance" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" :icon="useRenderIcon(Search)" @click="onSearch" class="mr-2">
搜索
</el-button>
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm" class="mr-2">
重置
</el-button>
<el-button type="success" :loading="exportLoading" :icon="useRenderIcon('vscode-icons:file-type-excel2')"
@click="handleExport">
导出Excel
</el-button>
</el-form-item>
</el-form>
<div class="table-container">
<el-table ref="tableRef" v-loading="loading" :data="dataList" row-key="approvalId"
@selection-change="rows => multipleSelection = rows.map(r => r.approvalId)" border>
<el-table-column label="审批ID" prop="approvalId" width="80" />
<el-table-column label="订单ID" prop="orderId" width="80" />
<el-table-column label="商品ID" prop="goodsId" width="80" />
<el-table-column label="用户姓名" prop="name" width="100" />
<el-table-column label="手机号" prop="mobile" width="120" />
<el-table-column label="商品名称" prop="goodsName" />
<el-table-column label="商品封面" width="120">
<template #default="{ row }">
<div v-if="row.coverImg" class="flex gap-2">
<el-image v-for="(img, index) in row.coverImg.split(',')" :key="index" :src="img"
:preview-src-list="row.coverImg.split(',')" :z-index="9999" :preview-teleported="true"
:hide-on-click-modal="true" fit="cover" class="rounded" width="40" height="40" />
</div>
<span v-else>-\</span>
</template>
</el-table-column>
<el-table-column label="商品价格" prop="goodsPrice" width="90">
<template #default="{ row }">{{ row.goodsPrice }}元</template>
</el-table-column>
<el-table-column label="支付方式" prop="paymentMethod" width="100">
<template #default="{ row }">
{{ { wechat: '微信支付', balance: '余额支付' }[row.paymentMethod] || row.paymentMethod }}
</template>
</el-table-column>
<el-table-column label="退货数量" prop="returnQuantity" width="90" />
<el-table-column label="退款金额" prop="returnAmount" width="90">
<template #default="{ row }">{{ row.returnAmount }}元</template>
</el-table-column>
<el-table-column label="提交时间" prop="createTime" width="180">
<template #default="{ row }">
{{ row.createTime ? new Date(row.createTime).toLocaleString() : '-' }}
</template>
</el-table-column>
<el-table-column label="状态" prop="status" width="100">
<template #default="{ row }">
<el-tag :type="{ 1: 'warning', 2: 'success', 3: 'danger' }[row.status]">
{{ row.statusStr }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="审批时间" prop="approvalTime" width="180">
<template #default="{ row }">
{{ row.approvalTime ? new Date(row.approvalTime).toLocaleString() : '-' }}
</template>
</el-table-column>
<el-table-column label="退货图片" width="140">
<template #default="{ row }">
<div v-if="row.returnImages" class="flex gap-2">
<el-image v-for="(img, index) in row.returnImages.split(',')" :key="index" :src="img"
:preview-src-list="row.returnImages.split(',')" :z-index="9999" :preview-teleported="true"
:hide-on-click-modal="true" fit="cover" class="rounded" width="40" height="40" />
</div>
<span v-else>-\</span>
</template>
</el-table-column>
<el-table-column label="操作" width="120" fixed="right">
<template #default="{ row }">
<el-button type="primary" link :icon="useRenderIcon(View)" @click="showDetail(row)">
详情
</el-button>
<!-- <el-popconfirm :title="`确认删除审批记录#${row.approvalId}`"
@confirm="() => deleteReturnApprovalApi([row.approvalId])">
<template #reference>
<el-button type="danger" link :icon="useRenderIcon(Delete)">
删除
</el-button>
</template>
</el-popconfirm> -->
</template>
</el-table-column>
</el-table>
<el-pagination v-model:current-page="pagination.currentPage" v-model:page-size="pagination.pageSize"
:page-sizes="[10, 20, 50]" layout="total, sizes, prev, pager, next, jumper" :total="pagination.total"
@size-change="handlePaginationChange" @current-change="handlePaginationChange" class="pagination" />
</div>
<!-- 详情弹窗 -->
<el-dialog v-model="detailVisible" title="审批详情" width="50%">
<el-descriptions :column="2" border>
<el-descriptions-item label="退货说明">{{ currentDetail?.returnRemark || '无' }}</el-descriptions-item>
<el-descriptions-item label="审核说明">{{ currentDetail?.auditRemark || '无' }}</el-descriptions-item>
<el-descriptions-item label="退货图片" :span="2">
<div class="flex flex-wrap gap-2">
<el-image v-for="(img, index) in currentDetail?.returnImages?.split(',')" :key="index" :src="img"
:preview-src-list="currentDetail?.returnImages?.split(',')" :initial-index="index" fit="cover"
class="w-20 h-20 rounded" />
</div>
</el-descriptions-item>
<el-descriptions-item label="审核图片" :span="2" v-if="currentDetail?.auditImages?.length">
<div class="flex flex-wrap gap-2">
<el-image v-for="(img, index) in currentDetail?.auditImages?.split(',')" :key="index" :src="img"
:preview-src-list="currentDetail?.auditImages?.split(',')" fit="cover" class="w-20 h-20 rounded" />
</div>
</el-descriptions-item>
</el-descriptions>
</el-dialog>
</div>
</template>
<style scoped lang="scss">
.search-form {
:deep(.el-form-item) {
margin-bottom: 12px;
margin-right: 12px;
}
}
:deep(.el-image-viewer__wrapper) {
z-index: 9999 !important;
}
.table-container {
margin-top: 8px;
background-color: var(--el-bg-color);
border-radius: 4px;
padding: 16px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
display: flex;
flex-direction: column;
.el-table {
flex: 1;
overflow: hidden;
}
.pagination {
margin-top: 10px;
}
}
</style>