完善小程序

This commit is contained in:
xuqiuyun
2025-10-09 17:59:26 +08:00
parent 74b2edb510
commit f88383425f
46 changed files with 3477 additions and 185 deletions

View File

@@ -1,6 +1,7 @@
const { DeviceAlert, Device, User } = require('../models');
const { Op } = require('sequelize');
const logger = require('../utils/logger');
const ExcelExport = require('../utils/excelExport');
/**
* 设备预警控制器
@@ -416,6 +417,103 @@ class DeviceAlertController {
});
}
}
/**
* 导出设备预警列表到Excel
*/
static async exportToExcel(req, res) {
try {
const { alert_level, alert_type, status, is_read } = req.query;
// 构建查询条件
const where = {};
if (alert_level) where.alert_level = alert_level;
if (alert_type) where.alert_type = alert_type;
if (status) where.status = status;
if (is_read !== undefined) where.is_read = is_read === 'true';
// 查询所有符合条件的数据
const alerts = await DeviceAlert.findAll({
where,
include: [{
model: Device,
as: 'Device',
attributes: ['device_name', 'device_number', 'installation_location']
}],
order: [['alert_time', 'DESC']],
raw: true,
nest: true
});
// 状态映射
const levelMap = {
info: '信息',
warning: '警告',
critical: '严重'
};
const typeMap = {
temperature: '温度异常',
humidity: '湿度异常',
offline: '设备离线',
maintenance: '设备维护'
};
const statusMap = {
pending: '待处理',
processing: '处理中',
resolved: '已解决'
};
// 准备导出数据
const exportData = alerts.map(alert => ({
alert_title: alert.alert_title || '',
alert_level: ExcelExport.formatStatus(alert.alert_level, levelMap),
alert_type: ExcelExport.formatStatus(alert.alert_type, typeMap),
alert_content: alert.alert_content || '',
device_name: alert.Device?.device_name || '',
device_number: alert.Device?.device_number || '',
installation_location: alert.Device?.installation_location || '',
status: ExcelExport.formatStatus(alert.status, statusMap),
is_read: alert.is_read ? '已读' : '未读',
alert_time: ExcelExport.formatDate(alert.alert_time),
read_time: ExcelExport.formatDate(alert.read_time)
}));
// 定义列
const columns = [
{ header: '预警标题', key: 'alert_title', width: 30 },
{ header: '预警级别', key: 'alert_level', width: 12 },
{ header: '预警类型', key: 'alert_type', width: 15 },
{ header: '预警内容', key: 'alert_content', width: 40 },
{ header: '设备名称', key: 'device_name', width: 20 },
{ header: '设备编号', key: 'device_number', width: 20 },
{ header: '安装位置', key: 'installation_location', width: 30 },
{ header: '处理状态', key: 'status', width: 12 },
{ header: '阅读状态', key: 'is_read', width: 10 },
{ header: '预警时间', key: 'alert_time', width: 20 },
{ header: '阅读时间', key: 'read_time', width: 20 }
];
// 生成Excel
const buffer = await ExcelExport.exportToExcel(exportData, columns, '设备预警列表');
// 设置响应头
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
res.setHeader('Content-Disposition', `attachment; filename=device_alerts_${Date.now()}.xlsx`);
// 发送文件
res.send(buffer);
} catch (error) {
logger.error('导出设备预警失败:', error);
res.status(500).json({
success: false,
message: '导出失败',
error: error.message
});
}
}
}
module.exports = DeviceAlertController;

View File

@@ -2,6 +2,7 @@ const InstallationTask = require('../models/InstallationTask');
const User = require('../models/User');
const { Op, sequelize } = require('sequelize');
const logger = require('../utils/logger');
const ExcelExport = require('../utils/excelExport');
class InstallationTaskController {
@@ -472,6 +473,99 @@ class InstallationTaskController {
});
}
}
// 导出待安装任务列表到Excel
async exportToExcel(req, res) {
try {
const { policyNumber, keyword } = req.query;
// 构建查询条件使用数据库字段名因为raw:true模式
const whereConditions = {};
if (policyNumber) {
whereConditions.policy_number = { [Op.like]: `%${policyNumber}%` };
}
// 关键字搜索
if (keyword) {
whereConditions[Op.or] = [
{ application_number: { [Op.like]: `%${keyword}%` } },
{ policy_number: { [Op.like]: `%${keyword}%` } },
{ customer_name: { [Op.like]: `%${keyword}%` } },
{ installation_address: { [Op.like]: `%${keyword}%` } }
];
}
// 查询所有符合条件的数据
const tasks = await InstallationTask.findAll({
where: whereConditions,
order: [['created_at', 'DESC']]
});
console.log(`导出查询到 ${tasks.length} 条数据`);
// 准备导出数据Sequelize自动转换为驼峰格式
const exportData = tasks.map(task => {
const data = task.toJSON ? task.toJSON() : task;
return {
applicationNumber: data.applicationNumber || '',
policyNumber: data.policyNumber || '',
productName: data.productName || '',
customerName: data.customerName || '',
idType: data.idType || '',
idNumber: data.idNumber || '',
livestockSupplyType: data.livestockSupplyType || '',
installationStatus: data.installationStatus || '',
priority: data.priority || '',
installationAddress: data.installationAddress || '',
contactPhone: data.contactPhone || '',
taskGeneratedTime: ExcelExport.formatDate(data.taskGeneratedTime),
installationCompletedTime: ExcelExport.formatDate(data.installationCompletedTime),
createdAt: ExcelExport.formatDate(data.created_at || data.createdAt),
updatedAt: ExcelExport.formatDate(data.updated_at || data.updatedAt)
};
});
// 定义列
const columns = [
{ header: '申请单号', key: 'applicationNumber', width: 20 },
{ header: '保单编号', key: 'policyNumber', width: 20 },
{ header: '产品名称', key: 'productName', width: 25 },
{ header: '客户姓名', key: 'customerName', width: 15 },
{ header: '证件类型', key: 'idType', width: 12 },
{ header: '证件号码', key: 'idNumber', width: 20 },
{ header: '养殖生资种类', key: 'livestockSupplyType', width: 20 },
{ header: '安装状态', key: 'installationStatus', width: 12 },
{ header: '优先级', key: 'priority', width: 10 },
{ header: '安装地址', key: 'installationAddress', width: 30 },
{ header: '联系电话', key: 'contactPhone', width: 15 },
{ header: '任务生成时间', key: 'taskGeneratedTime', width: 20 },
{ header: '安装完成时间', key: 'installationCompletedTime', width: 20 },
{ header: '创建时间', key: 'createdAt', width: 20 },
{ header: '更新时间', key: 'updatedAt', width: 20 }
];
// 生成Excel
const buffer = await ExcelExport.exportToExcel(exportData, columns, '待安装任务列表');
// 设置响应头
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
res.setHeader('Content-Disposition', `attachment; filename=installation_tasks_${Date.now()}.xlsx`);
// 发送文件
res.send(buffer);
} catch (error) {
console.error('导出待安装任务失败:', error);
logger.error('导出待安装任务失败:', error);
res.status(500).json({
code: 500,
status: 'error',
message: '导出失败',
error: error.message
});
}
}
}
module.exports = new InstallationTaskController();

View File

@@ -1,6 +1,7 @@
const { InsuranceType } = require('../models');
const { Op } = require('sequelize');
const responseFormat = require('../utils/response');
const ExcelExport = require('../utils/excelExport');
// 获取保险类型列表
const getInsuranceTypes = async (req, res) => {
@@ -457,11 +458,59 @@ const updateInsuranceTypeStatus = async (req, res) => {
}
};
// 导出保险类型列表到Excel
const exportToExcel = async (req, res) => {
try {
const { name, status } = req.query;
const where = {};
if (name) where.name = { [Op.like]: `%${name}%` };
if (status) where.status = status;
const types = await InsuranceType.findAll({
where,
order: [['created_at', 'DESC']],
raw: true
});
const statusMap = { active: '启用', inactive: '停用' };
const exportData = types.map(type => ({
name: type.name || '',
coverage_amount: type.coverage_amount || 0,
premium_rate: type.premium_rate || 0,
applicable_livestock: type.applicable_livestock || '',
description: type.description || '',
status: ExcelExport.formatStatus(type.status, statusMap),
created_at: ExcelExport.formatDate(type.created_at)
}));
const columns = [
{ header: '险种名称', key: 'name', width: 20 },
{ header: '保额', key: 'coverage_amount', width: 15 },
{ header: '费率', key: 'premium_rate', width: 10 },
{ header: '适用牲畜', key: 'applicable_livestock', width: 20 },
{ header: '描述', key: 'description', width: 40 },
{ header: '状态', key: 'status', width: 10 },
{ header: '创建时间', key: 'created_at', width: 20 }
];
const buffer = await ExcelExport.exportToExcel(exportData, columns, '保险类型列表');
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
res.setHeader('Content-Disposition', `attachment; filename=insurance_types_${Date.now()}.xlsx`);
res.send(buffer);
} catch (error) {
console.error('导出保险类型失败:', error);
res.status(500).json(responseFormat.error('导出失败'));
}
};
module.exports = {
getInsuranceTypes,
getInsuranceTypeById,
createInsuranceType,
updateInsuranceType,
deleteInsuranceType,
updateInsuranceTypeStatus
updateInsuranceTypeStatus,
exportToExcel
};

View File

@@ -4,6 +4,7 @@ const LivestockType = require('../models/LivestockType');
const User = require('../models/User');
const responseFormat = require('../utils/response');
const { Op } = require('sequelize');
const ExcelExport = require('../utils/excelExport');
// 获取生资理赔列表
const getLivestockClaims = async (req, res) => {
@@ -540,6 +541,66 @@ const deleteLivestockClaim = async (req, res) => {
}
};
// 导出理赔列表到Excel
const exportToExcel = async (req, res) => {
try {
const { claim_number, claimant_name, status } = req.query;
const where = {};
if (claim_number) where.claim_number = { [Op.like]: `%${claim_number}%` };
if (claimant_name) where.claimant_name = { [Op.like]: `%${claimant_name}%` };
if (status) where.status = status;
const claims = await LivestockClaim.findAll({
where,
include: [{
model: LivestockPolicy,
as: 'policy',
attributes: ['policy_number']
}],
order: [['createdAt', 'DESC']],
raw: true,
nest: true
});
const statusMap = { pending: '待审核', approved: '已批准', rejected: '已拒绝', settled: '已理赔' };
const exportData = claims.map(claim => ({
claim_number: claim.claim_number || '',
policy_number: claim.policy?.policy_number || '',
claimant_name: claim.claimant_name || '',
claim_amount: claim.claim_amount || 0,
approved_amount: claim.approved_amount || 0,
claim_reason: claim.claim_reason || '',
status: ExcelExport.formatStatus(claim.status, statusMap),
claim_date: ExcelExport.formatDate(claim.claim_date),
settled_date: ExcelExport.formatDate(claim.settled_date),
createdAt: ExcelExport.formatDate(claim.createdAt)
}));
const columns = [
{ header: '理赔编号', key: 'claim_number', width: 20 },
{ header: '保单编号', key: 'policy_number', width: 20 },
{ header: '理赔人', key: 'claimant_name', width: 15 },
{ header: '理赔金额', key: 'claim_amount', width: 15 },
{ header: '批准金额', key: 'approved_amount', width: 15 },
{ header: '理赔原因', key: 'claim_reason', width: 30 },
{ header: '状态', key: 'status', width: 12 },
{ header: '理赔日期', key: 'claim_date', width: 15 },
{ header: '结算日期', key: 'settled_date', width: 15 },
{ header: '创建时间', key: 'createdAt', width: 20 }
];
const buffer = await ExcelExport.exportToExcel(exportData, columns, '理赔列表');
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
res.setHeader('Content-Disposition', `attachment; filename=livestock_claims_${Date.now()}.xlsx`);
res.send(buffer);
} catch (error) {
console.error('导出理赔记录失败:', error);
res.status(500).json(responseFormat.error('导出失败'));
}
};
module.exports = {
getLivestockClaims,
createLivestockClaim,
@@ -548,5 +609,6 @@ module.exports = {
deleteLivestockClaim,
reviewLivestockClaim,
updateLivestockClaimPayment,
getLivestockClaimStats
getLivestockClaimStats,
exportToExcel
};

View File

@@ -3,6 +3,7 @@ const LivestockType = require('../models/LivestockType');
const User = require('../models/User');
const responseFormat = require('../utils/response');
const { Op } = require('sequelize');
const ExcelExport = require('../utils/excelExport');
// 获取生资保单列表
const getLivestockPolicies = async (req, res) => {
@@ -337,6 +338,69 @@ const deleteLivestockPolicy = async (req, res) => {
}
};
// 导出生资保单列表到Excel
const exportToExcel = async (req, res) => {
try {
const { policy_no, farmer_name, policy_status } = req.query;
const where = {};
if (policy_no) where.policy_no = { [Op.like]: `%${policy_no}%` };
if (farmer_name) where.farmer_name = { [Op.like]: `%${farmer_name}%` };
if (policy_status) where.policy_status = policy_status;
const policies = await LivestockPolicy.findAll({
where,
include: [{
model: LivestockType,
as: 'livestockType',
attributes: ['name']
}],
order: [['created_at', 'DESC']],
raw: true,
nest: true
});
const statusMap = { active: '生效中', pending: '待生效', expired: '已过期', cancelled: '已取消' };
const paymentMap = { unpaid: '未支付', paid: '已支付', partial: '部分支付' };
const exportData = policies.map(policy => ({
policy_no: policy.policy_no || '',
farmer_name: policy.farmer_name || '',
farmer_phone: policy.farmer_phone || '',
livestock_type: policy.livestockType?.name || '',
insured_amount: policy.insured_amount || 0,
premium_amount: policy.premium_amount || 0,
policy_status: ExcelExport.formatStatus(policy.policy_status, statusMap),
payment_status: ExcelExport.formatStatus(policy.payment_status, paymentMap),
start_date: ExcelExport.formatDate(policy.start_date),
end_date: ExcelExport.formatDate(policy.end_date),
created_at: ExcelExport.formatDate(policy.created_at)
}));
const columns = [
{ header: '保单号', key: 'policy_no', width: 20 },
{ header: '农户姓名', key: 'farmer_name', width: 15 },
{ header: '联系电话', key: 'farmer_phone', width: 15 },
{ header: '牲畜类型', key: 'livestock_type', width: 15 },
{ header: '保额', key: 'insured_amount', width: 15 },
{ header: '保费', key: 'premium_amount', width: 15 },
{ header: '保单状态', key: 'policy_status', width: 12 },
{ header: '支付状态', key: 'payment_status', width: 12 },
{ header: '起始日期', key: 'start_date', width: 15 },
{ header: '结束日期', key: 'end_date', width: 15 },
{ header: '创建时间', key: 'created_at', width: 20 }
];
const buffer = await ExcelExport.exportToExcel(exportData, columns, '生资保单列表');
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
res.setHeader('Content-Disposition', `attachment; filename=livestock_policies_${Date.now()}.xlsx`);
res.send(buffer);
} catch (error) {
console.error('导出生资保单失败:', error);
res.status(500).json(responseFormat.error('导出失败'));
}
};
module.exports = {
getLivestockPolicies,
createLivestockPolicy,
@@ -344,5 +408,6 @@ module.exports = {
updateLivestockPolicy,
updateLivestockPolicyStatus,
deleteLivestockPolicy,
getLivestockPolicyStats
getLivestockPolicyStats,
exportToExcel
};

View File

@@ -1,6 +1,7 @@
const { OperationLog, User } = require('../models');
const { Op } = require('sequelize');
const ExcelJS = require('exceljs');
const ExcelExport = require('../utils/excelExport');
/**
* 操作日志控制器
@@ -339,6 +340,99 @@ class OperationLogController {
});
}
}
/**
* 导出操作日志列表到Excel
*/
async exportToExcel(req, res) {
try {
const { username, operation_type, operation_module, startDate, endDate } = req.query;
// 构建查询条件
const where = {};
if (username) {
where['$User.username$'] = { [Op.like]: `%${username}%` };
}
if (operation_type) where.operation_type = operation_type;
if (operation_module) where.operation_module = operation_module;
if (startDate && endDate) {
where.created_at = {
[Op.between]: [new Date(startDate), new Date(endDate)]
};
}
// 查询所有符合条件的数据
const logs = await OperationLog.findAll({
where,
include: [{
model: User,
as: 'User',
attributes: ['username', 'real_name']
}],
order: [['created_at', 'DESC']],
raw: true,
nest: true
});
// 操作类型映射
const typeMap = {
login: '登录',
logout: '登出',
create: '创建',
update: '更新',
delete: '删除',
view: '查看',
export: '导出'
};
const statusMap = {
success: '成功',
failure: '失败'
};
// 准备导出数据
const exportData = logs.map(log => ({
username: log.User?.username || '',
real_name: log.User?.real_name || '',
operation_type: ExcelExport.formatStatus(log.operation_type, typeMap),
operation_module: log.operation_module || '',
operation_desc: log.operation_desc || '',
ip_address: log.ip_address || '',
status: ExcelExport.formatStatus(log.status, statusMap),
created_at: ExcelExport.formatDate(log.created_at)
}));
// 定义列
const columns = [
{ header: '用户名', key: 'username', width: 15 },
{ header: '真实姓名', key: 'real_name', width: 15 },
{ header: '操作类型', key: 'operation_type', width: 12 },
{ header: '操作模块', key: 'operation_module', width: 20 },
{ header: '操作描述', key: 'operation_desc', width: 40 },
{ header: 'IP地址', key: 'ip_address', width: 20 },
{ header: '状态', key: 'status', width: 10 },
{ header: '操作时间', key: 'created_at', width: 20 }
];
// 生成Excel
const buffer = await ExcelExport.exportToExcel(exportData, columns, '操作日志');
// 设置响应头
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
res.setHeader('Content-Disposition', `attachment; filename=operation_logs_${Date.now()}.xlsx`);
// 发送文件
res.send(buffer);
} catch (error) {
console.error('导出操作日志失败:', error);
res.status(500).json({
status: 'error',
message: '导出失败',
error: error.message
});
}
}
}
module.exports = new OperationLogController();

View File

@@ -1,6 +1,7 @@
const { Policy, InsuranceApplication, InsuranceType, User } = require('../models');
const responseFormat = require('../utils/response');
const { Op } = require('sequelize');
const ExcelExport = require('../utils/excelExport');
// 获取保单列表
const getPolicies = async (req, res) => {
@@ -363,6 +364,64 @@ const deletePolicy = async (req, res) => {
}
};
// 导出保单列表到Excel
const exportToExcel = async (req, res) => {
try {
const { policy_number, policyholder_name, status } = req.query;
const where = {};
if (policy_number) where.policy_number = { [Op.like]: `%${policy_number}%` };
if (policyholder_name) where.policyholder_name = { [Op.like]: `%${policyholder_name}%` };
if (status) where.status = status;
const policies = await Policy.findAll({
where,
include: [{
model: InsuranceType,
as: 'InsuranceType',
attributes: ['name']
}],
order: [['created_at', 'DESC']],
raw: true,
nest: true
});
const statusMap = { active: '生效中', pending: '待生效', expired: '已过期', cancelled: '已取消' };
const exportData = policies.map(policy => ({
policy_number: policy.policy_number || '',
policyholder_name: policy.policyholder_name || '',
insurance_type_name: policy.InsuranceType?.name || '',
coverage_amount: policy.coverage_amount || 0,
premium_amount: policy.premium_amount || 0,
start_date: ExcelExport.formatDate(policy.start_date),
end_date: ExcelExport.formatDate(policy.end_date),
status: ExcelExport.formatStatus(policy.status, statusMap),
created_at: ExcelExport.formatDate(policy.created_at)
}));
const columns = [
{ header: '保单编号', key: 'policy_number', width: 20 },
{ header: '投保人', key: 'policyholder_name', width: 15 },
{ header: '险种', key: 'insurance_type_name', width: 20 },
{ header: '保额', key: 'coverage_amount', width: 15 },
{ header: '保费', key: 'premium_amount', width: 15 },
{ header: '开始日期', key: 'start_date', width: 15 },
{ header: '结束日期', key: 'end_date', width: 15 },
{ header: '状态', key: 'status', width: 12 },
{ header: '创建时间', key: 'created_at', width: 20 }
];
const buffer = await ExcelExport.exportToExcel(exportData, columns, '保单列表');
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
res.setHeader('Content-Disposition', `attachment; filename=policies_${Date.now()}.xlsx`);
res.send(buffer);
} catch (error) {
console.error('导出保单失败:', error);
res.status(500).json(responseFormat.error('导出失败'));
}
};
module.exports = {
getPolicies,
createPolicy,
@@ -370,5 +429,6 @@ module.exports = {
updatePolicy,
updatePolicyStatus,
deletePolicy,
getPolicyStats
getPolicyStats,
exportToExcel
};

View File

@@ -1,5 +1,6 @@
const { SupervisoryTask, User } = require('../models');
const { Op } = require('sequelize');
const ExcelExport = require('../utils/excelExport');
/**
* 监管任务控制器
@@ -522,6 +523,93 @@ class SupervisoryTaskController {
});
}
}
/**
* 导出监管任务列表到Excel
*/
static async exportToExcel(req, res) {
try {
const { policyNumber, customerName } = req.query;
// 构建查询条件
const where = {};
if (policyNumber) {
where.policyNumber = { [Op.like]: `%${policyNumber}%` };
}
if (customerName) {
where.customerName = { [Op.like]: `%${customerName}%` };
}
// 查询所有符合条件的数据
const tasks = await SupervisoryTask.findAll({
where,
order: [['createdAt', 'DESC']],
raw: true
});
// 状态映射
const statusMap = {
pending: '待处理',
processing: '处理中',
completed: '已完成',
rejected: '已拒绝'
};
const priorityMap = {
low: '低',
medium: '中',
high: '高',
urgent: '紧急'
};
// 准备导出数据
const exportData = tasks.map(task => ({
policyNumber: task.policyNumber || '',
customerName: task.customerName || '',
productName: task.productName || '',
insurancePeriod: task.insurancePeriod || '',
applicableAmount: task.applicableAmount || '',
taskStatus: ExcelExport.formatStatus(task.taskStatus, statusMap),
priority: ExcelExport.formatStatus(task.priority, priorityMap),
createdAt: ExcelExport.formatDate(task.createdAt),
updatedAt: ExcelExport.formatDate(task.updatedAt)
}));
// 定义列
const columns = [
{ header: '保单编号', key: 'policyNumber', width: 20 },
{ header: '客户姓名', key: 'customerName', width: 15 },
{ header: '产品名称', key: 'productName', width: 25 },
{ header: '保险期间', key: 'insurancePeriod', width: 25 },
{ header: '适用金额', key: 'applicableAmount', width: 15 },
{ header: '任务状态', key: 'taskStatus', width: 12 },
{ header: '优先级', key: 'priority', width: 12 },
{ header: '创建时间', key: 'createdAt', width: 20 },
{ header: '更新时间', key: 'updatedAt', width: 20 }
];
// 生成Excel
const buffer = await ExcelExport.exportToExcel(exportData, columns, '监管任务列表');
// 设置响应头
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
res.setHeader('Content-Disposition', `attachment; filename=supervision_tasks_${Date.now()}.xlsx`);
// 发送文件
res.send(buffer);
} catch (error) {
console.error('导出监管任务失败:', error);
res.status(500).json({
code: 500,
status: 'error',
message: '导出失败',
error: error.message
});
}
}
}
module.exports = SupervisoryTaskController;

View File

@@ -2,6 +2,7 @@ const { User, Role } = require('../models');
const { Op } = require('sequelize');
const responseFormat = require('../utils/response');
const crypto = require('crypto');
const ExcelExport = require('../utils/excelExport');
// 获取用户列表
const getUsers = async (req, res) => {
@@ -486,6 +487,84 @@ const getFixedTokenInfo = async (req, res) => {
}
};
// 导出用户列表到Excel
const exportToExcel = async (req, res) => {
try {
const { search, status } = req.query;
const whereClause = {};
if (search) {
whereClause[Op.or] = [
{ username: { [Op.like]: `%${search}%` } },
{ real_name: { [Op.like]: `%${search}%` } },
{ email: { [Op.like]: `%${search}%` } },
{ phone: { [Op.like]: `%${search}%` } }
];
}
if (status) whereClause.status = status;
// 查询所有符合条件的数据
const users = await User.findAll({
where: whereClause,
include: [{
model: Role,
as: 'role',
attributes: ['name']
}],
order: [['created_at', 'DESC']],
raw: true,
nest: true
});
// 状态映射
const statusMap = {
active: '活跃',
inactive: '禁用',
suspended: '暂停'
};
// 准备导出数据
const exportData = users.map(user => ({
id: user.id || '',
username: user.username || '',
real_name: user.real_name || '',
email: user.email || '',
phone: user.phone || '',
role_name: user.role?.name || '',
status: ExcelExport.formatStatus(user.status, statusMap),
created_at: ExcelExport.formatDate(user.created_at),
updated_at: ExcelExport.formatDate(user.updated_at)
}));
// 定义列
const columns = [
{ header: 'ID', key: 'id', width: 10 },
{ header: '用户名', key: 'username', width: 15 },
{ header: '真实姓名', key: 'real_name', width: 15 },
{ header: '邮箱', key: 'email', width: 25 },
{ header: '手机号', key: 'phone', width: 15 },
{ header: '角色', key: 'role_name', width: 12 },
{ header: '状态', key: 'status', width: 10 },
{ header: '创建时间', key: 'created_at', width: 20 },
{ header: '更新时间', key: 'updated_at', width: 20 }
];
// 生成Excel
const buffer = await ExcelExport.exportToExcel(exportData, columns, '用户列表');
// 设置响应头
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
res.setHeader('Content-Disposition', `attachment; filename=users_${Date.now()}.xlsx`);
// 发送文件
res.send(buffer);
} catch (error) {
console.error('导出用户列表失败:', error);
res.status(500).json(responseFormat.error('导出失败'));
}
};
module.exports = {
getUsers,
getUser,
@@ -500,5 +579,6 @@ module.exports = {
generateFixedToken,
regenerateFixedToken,
deleteFixedToken,
getFixedTokenInfo
getFixedTokenInfo,
exportToExcel
};