feat(user): 添加用户列表导出功能

- 新增 exportUsers API 接口用于导出用户数据
- 在用户管理页面添加导出按钮,仅超级管理员可见- 实现 handleExport 方法处理导出逻辑
- 使用 xlsx 库生成 Excel 文件并自动下载
- 添加搜索处理方法 handleSearch 优化查询体验
- 引入 computed 属性获取当前登录用户信息
- 更新搜索框事件处理为 handleSearch 方法- 调整导入/导出按钮显示权限控制逻辑
This commit is contained in:
2025-09-24 17:24:34 +08:00
parent 5516e994d5
commit ad2657a40a
4 changed files with 145 additions and 12 deletions

View File

@@ -1,5 +1,5 @@
VITE_APP_NAME=后台管理(开发环境)
VITE_API_URL=http://127.0.0.1:9200/api
#VITE_API_URL=http://127.0.0.1:9200/api
#VITE_SERVER_API_URL=http://127.0.0.1:8000/api

View File

@@ -282,3 +282,17 @@ export async function listAdminsByPhoneAll(params?: UserParam){
}
return Promise.reject(new Error(res.data.message));
}
/**
* 导出用户列表
*/
export async function exportUsers(params?: UserParam) {
const res = await request.get<Blob>(
SERVER_API_URL + '/system/user/export',
{
params,
responseType: 'blob'
}
);
return res.data;
}

View File

@@ -165,6 +165,15 @@ const columns = ref<ColumnItem[]>([
key: 'comments',
align: 'left'
},
{
title: '收益基数',
dataIndex: 'rate',
key: 'rate',
align: 'left',
customRender: () => {
return `0.007`;
}
},
{
title: '报备人信息',
key: 'applicantInfo',

View File

@@ -54,18 +54,21 @@
</template>
<span>批量删除</span>
</a-button>
<a-button type="dashed" class="ele-btn-icon" @click="openImport">
<template #icon>
<upload-outlined/>
</template>
<span>导入</span>
</a-button>
<template v-if="hasRole('superAdmin')">
<a-button type="dashed" class="ele-btn-icon" @click="openImport">
<template #icon>
<upload-outlined/>
</template>
<span>导入</span>
</a-button>
<a-button type="dashed" @click="handleExport">导出xls</a-button>
</template>
<a-input-search
allow-clear
v-model:value="searchText"
placeholder="请输入关键词"
@search="reload"
@pressEnter="reload"
@search="handleSearch"
@pressEnter="handleSearch"
/>
</a-space>
</template>
@@ -149,7 +152,7 @@
</template>
<script lang="ts" setup>
import {createVNode, ref, reactive} from 'vue';
import {createVNode, ref,computed, reactive} from 'vue';
import {message, Modal} from 'ant-design-vue/es';
import {
PlusOutlined,
@@ -177,16 +180,20 @@ import {
removeUser,
removeUsers,
updateUserPassword,
updateUser
updateUser,
listUsers
} from '@/api/system/user';
import type {User, UserParam} from '@/api/system/user/model';
import {toTreeData, uuid} from 'ele-admin-pro';
import {utils, writeFile} from 'xlsx';
import dayjs from 'dayjs';
import {listRoles} from '@/api/system/role';
import {listOrganizations} from '@/api/system/organization';
import {Organization} from '@/api/system/organization/model';
import {hasRole} from '@/utils/permission';
import {getPageTitle} from "@/utils/common";
import Extra from "./components/Extra.vue";
import {useUserStore} from '@/store/modules/user';
// 加载状态
const loading = ref(true);
@@ -208,7 +215,9 @@ const showInfo = ref(false);
const showImport = ref(false);
const userType = ref<number>();
const searchText = ref('');
const userStore = useUserStore();
// 当前用户信息
const loginUser = computed(() => userStore.info ?? {});
// 加载角色
const roles = ref<any[]>([]);
const filters = () => {
@@ -536,6 +545,107 @@ const updateIsAdmin = (row: User) => {
});
};
/* 搜索处理 */
const handleSearch = () => {
reload();
};
/* 导出功能 */
const handleExport = async () => {
if (loading.value) {
return;
}
loading.value = true;
message.loading('正在准备导出数据...', 0);
try {
const array: (string | number)[][] = [
[
'用户ID',
'头像',
'手机号码',
'真实姓名',
'昵称',
'性别',
'邮箱',
'可用余额',
'可用积分',
'注册来源',
'注册时间'
]
];
// 构建查询参数
const queryParams = {
keywords: searchText.value
};
// 按搜索结果导出
const list = await listUsers(queryParams);
if (!list || list.length === 0) {
message.warning('没有数据可以导出');
loading.value = false;
return;
}
list.forEach((user: User) => {
array.push([
`${user.userId || ''}`,
`${user.avatar ? '有头像' : '无头像'}`,
`${user.phone || ''}`,
`${user.realName || ''}`,
`${user.nickname || ''}`,
`${user.sex === '1' ? '男' : user.sex === '2' ? '女' : ''}`,
`${user.email || ''}`,
`${user.balance || '0'}`,
`${user.points || '0'}`,
`${user.platform || ''}`,
`${user.createTime || ''}`
]);
});
const sheetName = `导出用户列表${dayjs(new Date()).format('YYYYMMDD')}`;
const workbook = {
SheetNames: [sheetName],
Sheets: {}
};
const sheet = utils.aoa_to_sheet(array);
workbook.Sheets[sheetName] = sheet;
// 设置列宽
sheet['!cols'] = [
{wch: 10}, // 用户ID
{wch: 10}, // 头像
{wch: 15}, // 手机号码
{wch: 15}, // 真实姓名
{wch: 15}, // 昵称
{wch: 8}, // 性别
{wch: 20}, // 邮箱
{wch: 12}, // 可用余额
{wch: 12}, // 可用积分
{wch: 12}, // 注册来源
{wch: 20} // 注册时间
];
message.destroy();
message.loading('正在生成Excel文件...', 0);
setTimeout(() => {
writeFile(workbook, `${sheetName}.xlsx`);
loading.value = false;
message.destroy();
message.success(`成功导出 ${list.length} 条记录`);
}, 1000);
} catch (error: any) {
loading.value = false;
message.destroy();
message.error(error.message || '导出失败,请重试');
}
};
/* 自定义行属性 */
const customRow = (record: User) => {
return {