feat(approvalCenter): 添加审批中心列表页功能及搜索过滤

- 在接口定义中添加handleStatus和searchStr字段支持搜索过滤
- 实现审批列表的数据加载、分页和搜索功能
- 添加表格展示及状态标签显示
- 实现不同菜单下的数据切换和加载
This commit is contained in:
dzq 2025-06-24 15:45:26 +08:00
parent 52f8cbff4a
commit 80dc7ecd58
2 changed files with 231 additions and 45 deletions

View File

@ -18,6 +18,18 @@ export interface SearchReturnApprovalQuery extends BasePageQuery {
* 0 1 * 0 1
*/ */
approvalType: number; approvalType: number;
/**
*
* @remarks
* 0:待处理 1:已处理
*/
handleStatus?: number;
/**
*
* @remarks
*
*/
searchStr?: string;
} }
/** 退货审批DTO */ /** 退货审批DTO */

View File

@ -1,5 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, markRaw } from 'vue'; import { ref, computed, markRaw, watch, onMounted } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { PureTableBar } from "@/components/RePureTableBar";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import { import {
Calendar, Calendar,
Briefcase, Briefcase,
@ -20,7 +23,11 @@ import {
RefreshRight, RefreshRight,
Wallet, Wallet,
CreditCard, CreditCard,
Search,
Refresh
} from '@element-plus/icons-vue'; } from '@element-plus/icons-vue';
import { getReturnApprovalListApi } from '@/api/shop/approval';
import { debounce } from "@pureadmin/utils";
defineOptions({ defineOptions({
name: "approvalCenter" name: "approvalCenter"
@ -33,7 +40,23 @@ const activeMenu = ref('apply');
const activeTab = ref('all'); const activeTab = ref('all');
// //
const searchKey = ref(''); const searchFormParams = ref({
status: null,
searchStr: null
});
//
const pagination = ref({
pageSize: 5,
currentPage: 1,
total: 0
});
//
const pendingList = ref([]);
const processedList = ref([]);
const ccList = ref([]);
const submittedList = ref([]);
const loading = ref(false);
const multipleSelection = ref([]);
// //
const applicationData = ref({ const applicationData = ref({
@ -51,18 +74,12 @@ const applicationData = ref({
{ icon: markRaw(Wallet), name: '退款', color: '#795548' } { icon: markRaw(Wallet), name: '退款', color: '#795548' }
], ],
}); });
applicationData.value.all = [...applicationData.value.shop, ...applicationData.value.other];
// //
applicationData.value.all = [
...applicationData.value.shop,
...applicationData.value.other,
];
//
const filteredApplications = computed(() => { const filteredApplications = computed(() => {
const data = applicationData.value[activeTab.value] || []; const data = applicationData.value[activeTab.value] || [];
if (!searchKey.value) return data; return data;
return data.filter(item => item.name.includes(searchKey.value));
}); });
// //
@ -75,15 +92,105 @@ const handleTabChange = (tab: any) => {
activeTab.value = tab.name; activeTab.value = tab.name;
}; };
// //
const handleSearch = () => { const onSearch = () => {
console.log('搜索关键词:', searchKey.value); pagination.value.currentPage = 1;
loadData();
}; };
//
const debouncedSearch = debounce(onSearch, 500);
//
watch(
() => searchFormParams.value.searchStr,
(newVal) => {
debouncedSearch();
}
);
//
const resetForm = () => {
Object.assign(searchFormParams.value, {
approvalId: null,
orderId: null,
goodsId: null,
status: null,
approvalTime: null,
paymentMethod: null
});
onSearch();
};
//
const handlePaginationChange = () => loadData();
//
const loadData = async () => {
if (activeMenu.value !== 'received-pending' && activeMenu.value !== 'received-processed') {
return;
}
loading.value = true;
try {
const params = {
...searchFormParams.value,
approvalType: 0,
pageSize: pagination.value.pageSize,
pageNum: pagination.value.currentPage,
handleStatus: activeMenu.value === 'received-pending' ? 0 : activeMenu.value === 'received-processed' ? 1 : undefined
};
const { data } = await getReturnApprovalListApi(params);
const formattedData = data.rows.map(item => ({
...item,
statusStr: { 1: '待审核', 2: '已通过', 3: '已驳回' }[item.status],
paymentMethodStr: { wechat: '微信支付', balance: '余额支付' }[item.paymentMethod] || item.paymentMethod
}));
switch (activeMenu.value) {
case 'received-pending': pendingList.value = formattedData; break;
case 'received-processed': processedList.value = formattedData; break;
}
pagination.value.total = data.total;
} catch (error) {
console.error('加载数据失败', error);
ElMessage.error('加载数据失败');
} finally {
loading.value = false;
}
};
//
watch(activeMenu, () => {
if (['received-pending', 'received-processed', 'cc', 'submitted-sent'].includes(activeMenu.value)) {
loadData();
}
});
//
const currentList = computed(() => {
switch (activeMenu.value) {
case 'received-pending': return pendingList.value;
case 'received-processed': return processedList.value;
case 'cc': return ccList.value;
case 'submitted-sent': return submittedList.value;
default: return [];
}
});
// //
const handleCardClick = (item: any) => { const handleCardClick = (item: any) => {
console.log('点击申请类型:', item.name); console.log('点击申请类型:', item.name);
}; };
//
const handleSelectionChange = (val) => {
multipleSelection.value = val;
};
onMounted(() => {
if (['received-pending', 'received-processed', 'cc', 'submitted-sent'].includes(activeMenu.value)) {
loadData();
}
});
</script> </script>
@ -92,38 +199,21 @@ const handleCardClick = (item: any) => {
<!-- 左侧导航栏 --> <!-- 左侧导航栏 -->
<div class="sidebar"> <div class="sidebar">
<div class="custom-menu"> <div class="custom-menu">
<!-- 发起申请无子类 -->
<div class="menu-item" :class="{ 'active': activeMenu === 'apply' }" @click="handleMenuSelect('apply')"> <div class="menu-item" :class="{ 'active': activeMenu === 'apply' }" @click="handleMenuSelect('apply')">
发起申请 发起申请
</div> </div>
<!-- 我收到的有子类 -->
<div class="sub-menu"> <div class="sub-menu">
<div class="sub-menu-title"><span>我收到的</span></div> <div class="sub-menu-title"><span>我收到的</span></div>
<div class="sub-menu-items"> <div class="sub-menu-items">
<div class="menu-item child" :class="{ 'active': activeMenu === 'received-pending' }" <div class="menu-item child" :class="{ 'active': activeMenu === 'received-pending' }" @click="handleMenuSelect('received-pending')">待处理</div>
@click="handleMenuSelect('received-pending')"> <div class="menu-item child" :class="{ 'active': activeMenu === 'received-processed' }" @click="handleMenuSelect('received-processed')">已处理</div>
待处理 <div class="menu-item child" :class="{ 'active': activeMenu === 'cc' }" @click="handleMenuSelect('cc')">抄送我的</div>
</div>
<div class="menu-item child" :class="{ 'active': activeMenu === 'received-processed' }"
@click="handleMenuSelect('received-processed')">
已处理
</div>
<div class="menu-item child" :class="{ 'active': activeMenu === 'cc' }"
@click="handleMenuSelect('cc')">
已处理
</div>
</div> </div>
</div> </div>
<!-- 我提交的有子类 -->
<div class="sub-menu"> <div class="sub-menu">
<div class="sub-menu-title"><span>我提交的</span></div> <div class="sub-menu-title"><span>我提交的</span></div>
<div class="sub-menu-items"> <div class="sub-menu-items">
<div class="menu-item child" :class="{ 'active': activeMenu === 'submitted-sent' }" <div class="menu-item child" :class="{ 'active': activeMenu === 'submitted-sent' }" @click="handleMenuSelect('submitted-sent')">已提交</div>
@click="handleMenuSelect('submitted-sent')">
已提交
</div>
</div> </div>
</div> </div>
</div> </div>
@ -132,25 +222,88 @@ const handleCardClick = (item: any) => {
<!-- 右侧内容区域 --> <!-- 右侧内容区域 -->
<div class="content"> <div class="content">
<!-- 顶部导航标签栏+搜索 --> <!-- 顶部导航标签栏+搜索 -->
<div class="content-header"> <div class="content-header" v-if="activeMenu === 'apply'">
<el-tabs v-model="activeTab" type="card" @tab-click="handleTabChange"> <el-tabs v-model="activeTab" type="card" @tab-click="handleTabChange">
<el-tab-pane label="全部" name="all"></el-tab-pane> <el-tab-pane label="全部" name="all"></el-tab-pane>
<el-tab-pane label="借还审批" name="shop"></el-tab-pane> <el-tab-pane label="借还审批" name="shop"></el-tab-pane>
<el-tab-pane label="其他" name="other"></el-tab-pane> <el-tab-pane label="其他" name="other"></el-tab-pane>
</el-tabs> </el-tabs>
<el-input v-model="searchKey" placeholder="搜索" prefix-icon="ep:search" class="search-input"
@keydown.enter.prevent="handleSearch" />
</div> </div>
<!-- 申请类型列表根据标签栏切换 --> <!-- 搜索表单 -->
<div class="application-list"> <el-form v-if="activeMenu !== 'apply'" :inline="true" :model="searchFormParams" class="search-form bg-bg_color flex w-[99/100]">
<el-form-item prop="approvalId">
<el-input @keydown.enter.prevent="onSearch" v-model.number="searchFormParams.searchStr" placeholder="请输入申请人/商品" clearable class="!w-[250px]" />
</el-form-item>
</el-form>
<!-- 列表视图 -->
<div v-if="activeMenu !== 'apply'" class="approval-list">
<el-table
:data="currentList"
v-loading="loading"
border
style="width: 100%"
@selection-change="handleSelectionChange"
row-key="approvalId"
>
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column prop="approvalId" label="审批ID" width="100"></el-table-column>
<el-table-column prop="name" label="用户姓名" width="100"></el-table-column>
<el-table-column prop="mobile" label="手机号" width="120"></el-table-column>
<el-table-column prop="goodsName" label="商品名称"></el-table-column>
<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 prop="goodsPrice" label="商品价格" width="100">
<template #default="{ row }">{{ row.goodsPrice }}</template>
</el-table-column>
<el-table-column prop="paymentMethodStr" label="支付方式" width="100"></el-table-column>
<el-table-column prop="returnQuantity" label="归还数量" width="100"></el-table-column>
<el-table-column prop="returnAmount" label="退款金额" width="100">
<template #default="{ row }">{{ row.returnAmount }}</template>
</el-table-column>
<el-table-column prop="createTime" label="提交时间" width="180">
<template #default="{ row }">{{ row.createTime ? new Date(row.createTime).toLocaleString() : '-' }}</template>
</el-table-column>
<el-table-column prop="statusStr" label="状态" 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 prop="approvalTime" label="审批时间" width="180">
<template #default="{ row }">{{ row.approvalTime ? new Date(row.approvalTime).toLocaleString() : '-' }}</template>
</el-table-column>
<el-table-column label="操作" width="180" fixed="right">
<template #default="scope">
<el-button size="small" type="text">查看</el-button>
<el-button size="small" type="text" v-if="activeMenu === 'received-pending'">处理</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
v-model:current-page="pagination.currentPage"
v-model:page-size="pagination.pageSize"
:page-sizes="[5, 10, 20, 50]"
layout="total, sizes, prev, pager, next, jumper"
:total="pagination.total"
@size-change="handlePaginationChange"
@current-change="handlePaginationChange"
class="pagination mt-4"
/>
</div>
<!-- 申请类型列表 -->
<div class="application-list" v-if="activeMenu === 'apply'">
<el-row :gutter="16"> <el-row :gutter="16">
<el-col v-for="(item, index) in filteredApplications" :key="index" :xs="24" :sm="12" :md="8" :lg="6" :xl="4"> <el-col v-for="(item, index) in filteredApplications" :key="index" :xs="24" :sm="12" :md="8" :lg="6" :xl="4">
<div class="application-card" @click="handleCardClick(item)"> <div class="application-card" @click="handleCardClick(item)">
<el-icon class="card-icon" :style="{ color: item.color }"> <el-icon class="card-icon" :style="{ color: item.color }"><component :is="item.icon" /></el-icon>
<component :is="item.icon" />
</el-icon>
<div class="card-name">{{ item.name }}</div> <div class="card-name">{{ item.name }}</div>
</div> </div>
</el-col> </el-col>
@ -303,5 +456,26 @@ const handleCardClick = (item: any) => {
color: #333; color: #333;
} }
} }
/* 审批列表样式 */
.approval-list {
.el-table {
overflow: hidden;
}
.el-table__header th {
background-color: #f8f9fa;
font-weight: 500;
}
.el-button--text {
color: #409eff;
&:hover {
color: #66b1ff;
}
}
}
} }
</style> </style>