完善小程序
This commit is contained in:
@@ -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;
|
||||
@@ -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();
|
||||
@@ -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
|
||||
};
|
||||
@@ -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
|
||||
};
|
||||
@@ -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
|
||||
};
|
||||
@@ -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();
|
||||
@@ -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
|
||||
};
|
||||
@@ -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;
|
||||
@@ -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
|
||||
};
|
||||
326
insurance_backend/package-lock.json
generated
326
insurance_backend/package-lock.json
generated
@@ -2386,6 +2386,42 @@
|
||||
"node": ">=0.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/builtin-modules": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmmirror.com/builtin-modules/-/builtin-modules-3.3.0.tgz",
|
||||
"integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/builtins": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/builtins/-/builtins-5.1.0.tgz",
|
||||
"integrity": "sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"semver": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/builtins/node_modules/semver": {
|
||||
"version": "7.7.3",
|
||||
"resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.3.tgz",
|
||||
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/busboy": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmmirror.com/busboy/-/busboy-1.6.0.tgz",
|
||||
@@ -3645,6 +3681,35 @@
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-compat-utils": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmmirror.com/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz",
|
||||
"integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"semver": "^7.5.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-compat-utils/node_modules/semver": {
|
||||
"version": "7.7.3",
|
||||
"resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.3.tgz",
|
||||
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-config-standard": {
|
||||
"version": "17.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz",
|
||||
@@ -3739,6 +3804,28 @@
|
||||
"eslint": ">=4.19.1"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-es-x": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmmirror.com/eslint-plugin-es-x/-/eslint-plugin-es-x-7.8.0.tgz",
|
||||
"integrity": "sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
"https://github.com/sponsors/ota-meshi",
|
||||
"https://opencollective.com/eslint"
|
||||
],
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.1.2",
|
||||
"@eslint-community/regexpp": "^4.11.0",
|
||||
"eslint-compat-utils": "^0.5.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.18.0 || >=16.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-import": {
|
||||
"version": "2.32.0",
|
||||
"resolved": "https://registry.npmmirror.com/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz",
|
||||
@@ -3793,6 +3880,48 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-n": {
|
||||
"version": "16.6.2",
|
||||
"resolved": "https://registry.npmmirror.com/eslint-plugin-n/-/eslint-plugin-n-16.6.2.tgz",
|
||||
"integrity": "sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"builtins": "^5.0.1",
|
||||
"eslint-plugin-es-x": "^7.5.0",
|
||||
"get-tsconfig": "^4.7.0",
|
||||
"globals": "^13.24.0",
|
||||
"ignore": "^5.2.4",
|
||||
"is-builtin-module": "^3.2.1",
|
||||
"is-core-module": "^2.12.1",
|
||||
"minimatch": "^3.1.2",
|
||||
"resolve": "^1.22.2",
|
||||
"semver": "^7.5.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/mysticatea"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-n/node_modules/semver": {
|
||||
"version": "7.7.3",
|
||||
"resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.3.tgz",
|
||||
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-node": {
|
||||
"version": "11.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz",
|
||||
@@ -4637,6 +4766,19 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/get-tsconfig": {
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmmirror.com/get-tsconfig/-/get-tsconfig-4.12.0.tgz",
|
||||
"integrity": "sha512-LScr2aNr2FbjAjZh2C6X6BxRx1/x+aTDExct/xyq2XKbYOiG5c0aK7pMsSuyc0brz3ibr/lbQiHD9jzt4lccJw==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"resolve-pkg-maps": "^1.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/glob": {
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz",
|
||||
@@ -5113,6 +5255,22 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-builtin-module": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmmirror.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz",
|
||||
"integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"builtin-modules": "^3.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/is-callable": {
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmmirror.com/is-callable/-/is-callable-1.2.7.tgz",
|
||||
@@ -7225,6 +7383,12 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/openapi-types": {
|
||||
"version": "12.1.3",
|
||||
"resolved": "https://registry.npmmirror.com/openapi-types/-/openapi-types-12.1.3.tgz",
|
||||
"integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/optionator": {
|
||||
"version": "0.9.4",
|
||||
"resolved": "https://registry.npmmirror.com/optionator/-/optionator-0.9.4.tgz",
|
||||
@@ -7995,6 +8159,16 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve-pkg-maps": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
|
||||
"integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve.exports": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/resolve.exports/-/resolve.exports-2.0.3.tgz",
|
||||
@@ -10869,7 +11043,8 @@
|
||||
"@redis/bloom": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/@redis/bloom/-/bloom-1.2.0.tgz",
|
||||
"integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg=="
|
||||
"integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==",
|
||||
"requires": {}
|
||||
},
|
||||
"@redis/client": {
|
||||
"version": "1.6.1",
|
||||
@@ -10891,22 +11066,26 @@
|
||||
"@redis/graph": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/@redis/graph/-/graph-1.1.1.tgz",
|
||||
"integrity": "sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw=="
|
||||
"integrity": "sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==",
|
||||
"requires": {}
|
||||
},
|
||||
"@redis/json": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmmirror.com/@redis/json/-/json-1.0.7.tgz",
|
||||
"integrity": "sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ=="
|
||||
"integrity": "sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ==",
|
||||
"requires": {}
|
||||
},
|
||||
"@redis/search": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/@redis/search/-/search-1.2.0.tgz",
|
||||
"integrity": "sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw=="
|
||||
"integrity": "sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw==",
|
||||
"requires": {}
|
||||
},
|
||||
"@redis/time-series": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/@redis/time-series/-/time-series-1.1.0.tgz",
|
||||
"integrity": "sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g=="
|
||||
"integrity": "sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g==",
|
||||
"requires": {}
|
||||
},
|
||||
"@rtsao/scc": {
|
||||
"version": "1.1.0",
|
||||
@@ -11127,7 +11306,8 @@
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmmirror.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
|
||||
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
"agent-base": {
|
||||
"version": "6.0.2",
|
||||
@@ -11654,6 +11834,32 @@
|
||||
"resolved": "https://registry.npmmirror.com/buffers/-/buffers-0.1.1.tgz",
|
||||
"integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ=="
|
||||
},
|
||||
"builtin-modules": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmmirror.com/builtin-modules/-/builtin-modules-3.3.0.tgz",
|
||||
"integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
|
||||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"builtins": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/builtins/-/builtins-5.1.0.tgz",
|
||||
"integrity": "sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"semver": "^7.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "7.7.3",
|
||||
"resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.3.tgz",
|
||||
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
|
||||
"dev": true,
|
||||
"peer": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"busboy": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmmirror.com/busboy/-/busboy-1.6.0.tgz",
|
||||
@@ -12129,7 +12335,8 @@
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmmirror.com/dedent/-/dedent-1.7.0.tgz",
|
||||
"integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==",
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
"deep-is": {
|
||||
"version": "0.1.4",
|
||||
@@ -12593,11 +12800,31 @@
|
||||
"text-table": "^0.2.0"
|
||||
}
|
||||
},
|
||||
"eslint-compat-utils": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmmirror.com/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz",
|
||||
"integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"semver": "^7.5.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "7.7.3",
|
||||
"resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.3.tgz",
|
||||
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
|
||||
"dev": true,
|
||||
"peer": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"eslint-config-standard": {
|
||||
"version": "17.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz",
|
||||
"integrity": "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==",
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
"eslint-import-resolver-node": {
|
||||
"version": "0.3.9",
|
||||
@@ -12651,6 +12878,18 @@
|
||||
"regexpp": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"eslint-plugin-es-x": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmmirror.com/eslint-plugin-es-x/-/eslint-plugin-es-x-7.8.0.tgz",
|
||||
"integrity": "sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@eslint-community/eslint-utils": "^4.1.2",
|
||||
"@eslint-community/regexpp": "^4.11.0",
|
||||
"eslint-compat-utils": "^0.5.1"
|
||||
}
|
||||
},
|
||||
"eslint-plugin-import": {
|
||||
"version": "2.32.0",
|
||||
"resolved": "https://registry.npmmirror.com/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz",
|
||||
@@ -12698,6 +12937,35 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"eslint-plugin-n": {
|
||||
"version": "16.6.2",
|
||||
"resolved": "https://registry.npmmirror.com/eslint-plugin-n/-/eslint-plugin-n-16.6.2.tgz",
|
||||
"integrity": "sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"builtins": "^5.0.1",
|
||||
"eslint-plugin-es-x": "^7.5.0",
|
||||
"get-tsconfig": "^4.7.0",
|
||||
"globals": "^13.24.0",
|
||||
"ignore": "^5.2.4",
|
||||
"is-builtin-module": "^3.2.1",
|
||||
"is-core-module": "^2.12.1",
|
||||
"minimatch": "^3.1.2",
|
||||
"resolve": "^1.22.2",
|
||||
"semver": "^7.5.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "7.7.3",
|
||||
"resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.3.tgz",
|
||||
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
|
||||
"dev": true,
|
||||
"peer": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"eslint-plugin-node": {
|
||||
"version": "11.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz",
|
||||
@@ -12716,7 +12984,8 @@
|
||||
"version": "6.6.0",
|
||||
"resolved": "https://registry.npmmirror.com/eslint-plugin-promise/-/eslint-plugin-promise-6.6.0.tgz",
|
||||
"integrity": "sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ==",
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
"eslint-scope": {
|
||||
"version": "7.2.2",
|
||||
@@ -13314,6 +13583,16 @@
|
||||
"get-intrinsic": "^1.2.6"
|
||||
}
|
||||
},
|
||||
"get-tsconfig": {
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmmirror.com/get-tsconfig/-/get-tsconfig-4.12.0.tgz",
|
||||
"integrity": "sha512-LScr2aNr2FbjAjZh2C6X6BxRx1/x+aTDExct/xyq2XKbYOiG5c0aK7pMsSuyc0brz3ibr/lbQiHD9jzt4lccJw==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"resolve-pkg-maps": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz",
|
||||
@@ -13632,6 +13911,16 @@
|
||||
"has-tostringtag": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"is-builtin-module": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmmirror.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz",
|
||||
"integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"builtin-modules": "^3.3.0"
|
||||
}
|
||||
},
|
||||
"is-callable": {
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmmirror.com/is-callable/-/is-callable-1.2.7.tgz",
|
||||
@@ -14156,7 +14445,8 @@
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmmirror.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz",
|
||||
"integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==",
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
"jest-regex-util": {
|
||||
"version": "29.6.3",
|
||||
@@ -15219,6 +15509,12 @@
|
||||
"mimic-fn": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"openapi-types": {
|
||||
"version": "12.1.3",
|
||||
"resolved": "https://registry.npmmirror.com/openapi-types/-/openapi-types-12.1.3.tgz",
|
||||
"integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==",
|
||||
"peer": true
|
||||
},
|
||||
"optionator": {
|
||||
"version": "0.9.4",
|
||||
"resolved": "https://registry.npmmirror.com/optionator/-/optionator-0.9.4.tgz",
|
||||
@@ -15768,6 +16064,13 @@
|
||||
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
|
||||
"dev": true
|
||||
},
|
||||
"resolve-pkg-maps": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
|
||||
"integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
|
||||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"resolve.exports": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/resolve.exports/-/resolve.exports-2.0.3.tgz",
|
||||
@@ -17020,7 +17323,8 @@
|
||||
"version": "8.13.0",
|
||||
"resolved": "https://registry.npmmirror.com/ws/-/ws-8.13.0.tgz",
|
||||
"integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
"xmlchars": {
|
||||
"version": "2.2.0",
|
||||
|
||||
@@ -83,6 +83,47 @@ const { jwtAuth } = require('../middleware/auth');
|
||||
*/
|
||||
router.get('/stats', jwtAuth, deviceAlertController.getAlertStats);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/device-alerts/export:
|
||||
* get:
|
||||
* tags:
|
||||
* - 设备预警
|
||||
* summary: 导出设备预警列表到Excel
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: query
|
||||
* name: alert_level
|
||||
* schema:
|
||||
* type: string
|
||||
* description: 预警级别
|
||||
* - in: query
|
||||
* name: alert_type
|
||||
* schema:
|
||||
* type: string
|
||||
* description: 预警类型
|
||||
* - in: query
|
||||
* name: status
|
||||
* schema:
|
||||
* type: string
|
||||
* description: 处理状态
|
||||
* - in: query
|
||||
* name: is_read
|
||||
* schema:
|
||||
* type: boolean
|
||||
* description: 是否已读
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 导出成功
|
||||
* content:
|
||||
* application/vnd.openxmlformats-officedocument.spreadsheetml.sheet:
|
||||
* schema:
|
||||
* type: string
|
||||
* format: binary
|
||||
*/
|
||||
router.get('/export', jwtAuth, deviceAlertController.exportToExcel);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/device-alerts:
|
||||
|
||||
@@ -10,6 +10,50 @@ const { jwtAuth, requirePermission } = require('../middleware/auth');
|
||||
* description: 待安装任务管理
|
||||
*/
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/installation-tasks/stats:
|
||||
* get:
|
||||
* summary: 获取安装任务统计数据
|
||||
* tags: [InstallationTasks]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 获取成功
|
||||
*/
|
||||
router.get('/stats', jwtAuth, requirePermission('installation_tasks:read'), installationTaskController.getInstallationTaskStats);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/installation-tasks/export:
|
||||
* get:
|
||||
* summary: 导出待安装任务到Excel
|
||||
* tags: [InstallationTasks]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: query
|
||||
* name: policyNumber
|
||||
* schema:
|
||||
* type: string
|
||||
* description: 保单编号
|
||||
* - in: query
|
||||
* name: keyword
|
||||
* schema:
|
||||
* type: string
|
||||
* description: 关键字搜索
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 导出成功
|
||||
* content:
|
||||
* application/vnd.openxmlformats-officedocument.spreadsheetml.sheet:
|
||||
* schema:
|
||||
* type: string
|
||||
* format: binary
|
||||
*/
|
||||
router.get('/export', jwtAuth, requirePermission('installation_tasks:read'), installationTaskController.exportToExcel);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/installation-tasks:
|
||||
@@ -230,38 +274,4 @@ router.delete('/:id', jwtAuth, requirePermission('installation_tasks:delete'), i
|
||||
*/
|
||||
router.post('/batch/operate', jwtAuth, requirePermission('installation_tasks:update'), installationTaskController.batchOperateInstallationTasks);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/installation-tasks/export:
|
||||
* get:
|
||||
* summary: 导出待安装任务数据
|
||||
* tags: [InstallationTasks]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: query
|
||||
* name: ids
|
||||
* schema:
|
||||
* type: string
|
||||
* description: 任务ID列表(逗号分隔)
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 导出成功
|
||||
*/
|
||||
router.get('/export', jwtAuth, requirePermission('installation_tasks:read'), installationTaskController.exportInstallationTasks);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/installation-tasks/stats:
|
||||
* get:
|
||||
* summary: 获取安装任务统计数据
|
||||
* tags: [InstallationTasks]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 获取成功
|
||||
*/
|
||||
router.get('/stats', jwtAuth, requirePermission('installation_tasks:read'), installationTaskController.getInstallationTaskStats);
|
||||
|
||||
module.exports = router;
|
||||
@@ -174,6 +174,9 @@ router.get('/', jwtAuth, checkPermission('insurance_type', 'read'),
|
||||
* '500':
|
||||
* description: 服务器内部错误
|
||||
*/
|
||||
// 导出险种列表到Excel
|
||||
router.get('/export', jwtAuth, checkPermission('insurance_type', 'read'), insuranceTypeController.exportToExcel);
|
||||
|
||||
// 获取单个险种详情
|
||||
router.get('/:id', jwtAuth, checkPermission('insurance_type', 'read'),
|
||||
insuranceTypeController.getInsuranceTypeById
|
||||
|
||||
@@ -8,7 +8,8 @@ const {
|
||||
updateLivestockClaimPayment,
|
||||
getLivestockClaimStats,
|
||||
updateLivestockClaim,
|
||||
deleteLivestockClaim
|
||||
deleteLivestockClaim,
|
||||
exportToExcel
|
||||
} = require('../controllers/livestockClaimController');
|
||||
const { authenticateToken, requirePermission } = require('../middleware/auth');
|
||||
|
||||
@@ -33,6 +34,9 @@ router.get('/', authenticateToken, requirePermission('livestock_claim:read'), ge
|
||||
// 获取生资理赔统计
|
||||
router.get('/stats', authenticateToken, requirePermission('livestock_claim:read'), getLivestockClaimStats);
|
||||
|
||||
// 导出理赔列表到Excel
|
||||
router.get('/export', authenticateToken, requirePermission('livestock_claim:read'), exportToExcel);
|
||||
|
||||
// 获取单个生资理赔详情
|
||||
router.get('/:id', authenticateToken, requirePermission('livestock_claim:read'), getLivestockClaimById);
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@ const {
|
||||
updateLivestockPolicy,
|
||||
updateLivestockPolicyStatus,
|
||||
deleteLivestockPolicy,
|
||||
getLivestockPolicyStats
|
||||
getLivestockPolicyStats,
|
||||
exportToExcel
|
||||
} = require('../controllers/livestockPolicyController');
|
||||
const { jwtAuth, checkPermission } = require('../middleware/auth');
|
||||
|
||||
@@ -17,6 +18,9 @@ router.get('/', jwtAuth, checkPermission('insurance:policy', 'view'), getLivesto
|
||||
// 获取生资保单统计
|
||||
router.get('/stats', jwtAuth, checkPermission('insurance:policy', 'view'), getLivestockPolicyStats);
|
||||
|
||||
// 导出生资保单列表到Excel
|
||||
router.get('/export', jwtAuth, checkPermission('insurance:policy', 'view'), exportToExcel);
|
||||
|
||||
// 获取单个生资保单详情
|
||||
router.get('/:id', jwtAuth, checkPermission('insurance:policy', 'view'), getLivestockPolicyById);
|
||||
|
||||
|
||||
@@ -169,6 +169,9 @@ router.get('/', jwtAuth, checkPermission('system', 'read'), operationLogControll
|
||||
*/
|
||||
router.get('/stats', jwtAuth, checkPermission('system', 'read'), operationLogController.getOperationStats);
|
||||
|
||||
// 导出操作日志到Excel
|
||||
router.get('/export', jwtAuth, checkPermission('system', 'read'), operationLogController.exportToExcel);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/operation-logs/{id}:
|
||||
|
||||
@@ -18,6 +18,9 @@ router.post('/', jwtAuth, checkPermission('insurance:policy', 'create'),
|
||||
policyController.createPolicy
|
||||
);
|
||||
|
||||
// 导出保单列表到Excel
|
||||
router.get('/export', jwtAuth, checkPermission('insurance:policy', 'view'), policyController.exportToExcel);
|
||||
|
||||
// 获取单个保单详情
|
||||
router.get('/:id', jwtAuth, checkPermission('insurance:policy', 'view'),
|
||||
policyController.getPolicyById
|
||||
|
||||
@@ -10,6 +10,50 @@ const { jwtAuth, requirePermission } = require('../middleware/auth');
|
||||
* description: 监管任务管理
|
||||
*/
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/supervision-tasks/stats:
|
||||
* get:
|
||||
* summary: 获取监管任务统计信息
|
||||
* tags: [SupervisionTasks]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 获取成功
|
||||
*/
|
||||
router.get('/stats', jwtAuth, requirePermission('supervision_tasks:read'), SupervisoryTaskController.getStatistics);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/supervision-tasks/export:
|
||||
* get:
|
||||
* summary: 导出监管任务列表到Excel
|
||||
* tags: [SupervisionTasks]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: query
|
||||
* name: policyNumber
|
||||
* schema:
|
||||
* type: string
|
||||
* description: 保单编号
|
||||
* - in: query
|
||||
* name: customerName
|
||||
* schema:
|
||||
* type: string
|
||||
* description: 客户姓名
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 导出成功
|
||||
* content:
|
||||
* application/vnd.openxmlformats-officedocument.spreadsheetml.sheet:
|
||||
* schema:
|
||||
* type: string
|
||||
* format: binary
|
||||
*/
|
||||
router.get('/export', jwtAuth, requirePermission('supervision_tasks:read'), SupervisoryTaskController.exportToExcel);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/supervision-tasks:
|
||||
@@ -253,18 +297,4 @@ router.delete('/:id', jwtAuth, requirePermission('supervision_tasks:delete'), Su
|
||||
*/
|
||||
router.post('/batch/operate', jwtAuth, requirePermission('supervision_tasks:create'), SupervisoryTaskController.bulkCreate);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/supervision-tasks/stats:
|
||||
* get:
|
||||
* summary: 获取监管任务统计信息
|
||||
* tags: [SupervisionTasks]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 获取成功
|
||||
*/
|
||||
router.get('/stats', jwtAuth, requirePermission('supervision_tasks:read'), SupervisoryTaskController.getStatistics);
|
||||
|
||||
module.exports = router;
|
||||
@@ -13,6 +13,9 @@ router.get('/profile', jwtAuth, userController.getProfile);
|
||||
// 更新个人资料(不需要特殊权限,用户可以更新自己的资料)
|
||||
router.put('/profile', jwtAuth, userController.updateProfile);
|
||||
|
||||
// 导出用户列表(必须在 /:id 之前)
|
||||
router.get('/export', jwtAuth, checkPermission('user', 'read'), userController.exportToExcel);
|
||||
|
||||
// 获取单个用户信息
|
||||
router.get('/:id', jwtAuth, checkPermission('user', 'read'), userController.getUser);
|
||||
|
||||
|
||||
121
insurance_backend/scripts/add-export-routes.js
Normal file
121
insurance_backend/scripts/add-export-routes.js
Normal file
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* 批量为各个控制器添加导出路由的脚本
|
||||
* 使用说明:node scripts/add-export-routes.js
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// 需要添加导出功能的路由配置
|
||||
const routeConfigs = [
|
||||
{
|
||||
routeFile: 'routes/users.js',
|
||||
exportPath: '/export',
|
||||
controllerMethod: 'exportToExcel',
|
||||
permission: 'users:read',
|
||||
description: '导出用户列表到Excel'
|
||||
},
|
||||
{
|
||||
routeFile: 'routes/deviceAlerts.js',
|
||||
exportPath: '/export',
|
||||
controllerMethod: 'exportToExcel',
|
||||
permission: 'device_alerts:read',
|
||||
description: '导出设备预警列表到Excel'
|
||||
},
|
||||
{
|
||||
routeFile: 'routes/insuranceTypes.js',
|
||||
exportPath: '/export',
|
||||
controllerMethod: 'exportToExcel',
|
||||
permission: 'insurance_types:read',
|
||||
description: '导出保险类型列表到Excel'
|
||||
},
|
||||
{
|
||||
routeFile: 'routes/policies.js',
|
||||
exportPath: '/export',
|
||||
controllerMethod: 'exportToExcel',
|
||||
permission: 'policies:read',
|
||||
description: '导出保单列表到Excel'
|
||||
},
|
||||
{
|
||||
routeFile: 'routes/livestockClaims.js',
|
||||
exportPath: '/export',
|
||||
controllerMethod: 'exportToExcel',
|
||||
permission: 'livestock_claims:read',
|
||||
description: '导出理赔列表到Excel'
|
||||
},
|
||||
{
|
||||
routeFile: 'routes/installationTasks.js',
|
||||
exportPath: '/export',
|
||||
controllerMethod: 'exportToExcel',
|
||||
permission: 'installation_tasks:read',
|
||||
description: '导出待安装任务列表到Excel'
|
||||
},
|
||||
{
|
||||
routeFile: 'routes/livestockPolicies.js',
|
||||
exportPath: '/export',
|
||||
controllerMethod: 'exportToExcel',
|
||||
permission: 'livestock_policies:read',
|
||||
description: '导出生资保单列表到Excel'
|
||||
},
|
||||
{
|
||||
routeFile: 'routes/operationLogs.js',
|
||||
exportPath: '/export',
|
||||
controllerMethod: 'exportToExcel',
|
||||
permission: 'operation_logs:read',
|
||||
description: '导出操作日志到Excel'
|
||||
}
|
||||
];
|
||||
|
||||
console.log('🚀 开始为各个路由添加导出功能...\n');
|
||||
|
||||
routeConfigs.forEach(config => {
|
||||
const filePath = path.join(__dirname, '..', config.routeFile);
|
||||
|
||||
try {
|
||||
// 读取路由文件
|
||||
let content = fs.readFileSync(filePath, 'utf8');
|
||||
|
||||
// 检查是否已经存在导出路由
|
||||
if (content.includes(`router.get('${config.exportPath}'`) || content.includes(`router.get("${config.exportPath}"`)) {
|
||||
console.log(`⏭️ ${config.routeFile} - 导出路由已存在,跳过`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 在module.exports之前添加导出路由
|
||||
const exportRoute = `
|
||||
/**
|
||||
* @swagger
|
||||
* ${config.exportPath}:
|
||||
* get:
|
||||
* summary: ${config.description}
|
||||
* tags: [Export]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 导出成功
|
||||
* content:
|
||||
* application/vnd.openxmlformats-officedocument.spreadsheetml.sheet:
|
||||
* schema:
|
||||
* type: string
|
||||
* format: binary
|
||||
*/
|
||||
router.get('${config.exportPath}', jwtAuth, requirePermission('${config.permission}'), controller.${config.controllerMethod});
|
||||
|
||||
`;
|
||||
|
||||
// 在module.exports之前插入
|
||||
content = content.replace(/module\.exports\s*=\s*router;/, exportRoute + 'module.exports = router;');
|
||||
|
||||
// 写回文件
|
||||
fs.writeFileSync(filePath, content, 'utf8');
|
||||
console.log(`✅ ${config.routeFile} - 导出路由添加成功`);
|
||||
|
||||
} catch (error) {
|
||||
console.error(`❌ ${config.routeFile} - 添加失败: ${error.message}`);
|
||||
}
|
||||
});
|
||||
|
||||
console.log('\n✨ 路由添加完成!');
|
||||
console.log('⚠️ 注意:还需要为各个控制器添加 exportToExcel 方法');
|
||||
|
||||
31
insurance_backend/test-db-connection.js
Normal file
31
insurance_backend/test-db-connection.js
Normal file
@@ -0,0 +1,31 @@
|
||||
require('dotenv').config();
|
||||
const { sequelize, testConnection } = require('./config/database');
|
||||
|
||||
async function test() {
|
||||
console.log('测试数据库连接...');
|
||||
console.log('数据库配置:');
|
||||
console.log('- Host:', process.env.DB_HOST || '129.211.213.226');
|
||||
console.log('- Port:', process.env.DB_PORT || 9527);
|
||||
console.log('- Database:', process.env.DB_DATABASE || 'insurance_data');
|
||||
console.log('- User:', process.env.DB_USER || 'root');
|
||||
console.log('');
|
||||
|
||||
try {
|
||||
await sequelize.authenticate();
|
||||
console.log('✅ 数据库连接成功!');
|
||||
|
||||
// 测试查询
|
||||
const [results] = await sequelize.query('SELECT 1 as test');
|
||||
console.log('✅ 测试查询成功:', results);
|
||||
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.error('❌ 数据库连接失败:');
|
||||
console.error('错误信息:', error.message);
|
||||
console.error('错误详情:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
test();
|
||||
|
||||
52
insurance_backend/test-nxxmdata.js
Normal file
52
insurance_backend/test-nxxmdata.js
Normal file
@@ -0,0 +1,52 @@
|
||||
const { Sequelize } = require('sequelize');
|
||||
|
||||
// 测试连接到 nxxmdata 数据库
|
||||
const sequelize = new Sequelize({
|
||||
dialect: 'mysql',
|
||||
host: '129.211.213.226',
|
||||
port: 9527,
|
||||
database: 'nxxmdata',
|
||||
username: 'root',
|
||||
password: 'aiotAiot123!',
|
||||
logging: console.log,
|
||||
pool: {
|
||||
max: 5,
|
||||
min: 0,
|
||||
acquire: 30000,
|
||||
idle: 10000
|
||||
}
|
||||
});
|
||||
|
||||
async function test() {
|
||||
console.log('测试连接到 nxxmdata 数据库...');
|
||||
|
||||
try {
|
||||
await sequelize.authenticate();
|
||||
console.log('✅ 连接 nxxmdata 数据库成功!');
|
||||
|
||||
// 列出所有表
|
||||
const [tables] = await sequelize.query('SHOW TABLES');
|
||||
console.log('数据库中的表:', tables.length);
|
||||
|
||||
// 检查是否有 users 表
|
||||
const [userTables] = await sequelize.query("SHOW TABLES LIKE 'users'");
|
||||
if (userTables.length > 0) {
|
||||
console.log('✅ 找到 users 表');
|
||||
|
||||
// 查询用户数据
|
||||
const [users] = await sequelize.query('SELECT id, username, email FROM users LIMIT 5');
|
||||
console.log('用户数据:', users);
|
||||
} else {
|
||||
console.log('❌ 没有找到 users 表');
|
||||
}
|
||||
|
||||
await sequelize.close();
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.error('❌ 连接失败:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
test();
|
||||
|
||||
94
insurance_backend/utils/excelExport.js
Normal file
94
insurance_backend/utils/excelExport.js
Normal file
@@ -0,0 +1,94 @@
|
||||
const ExcelJS = require('exceljs');
|
||||
|
||||
/**
|
||||
* Excel导出工具类
|
||||
*/
|
||||
class ExcelExport {
|
||||
/**
|
||||
* 创建Excel工作簿并导出数据
|
||||
* @param {Array} data - 要导出的数据
|
||||
* @param {Array} columns - 列定义 [{ header: '列名', key: '字段名', width: 宽度 }]
|
||||
* @param {String} sheetName - 工作表名称
|
||||
* @returns {Promise<Buffer>} Excel文件Buffer
|
||||
*/
|
||||
static async exportToExcel(data, columns, sheetName = 'Sheet1') {
|
||||
const workbook = new ExcelJS.Workbook();
|
||||
const worksheet = workbook.addWorksheet(sheetName);
|
||||
|
||||
// 设置列
|
||||
worksheet.columns = columns;
|
||||
|
||||
// 设置表头样式
|
||||
worksheet.getRow(1).eachCell((cell) => {
|
||||
cell.font = { bold: true, color: { argb: 'FFFFFFFF' } };
|
||||
cell.fill = {
|
||||
type: 'pattern',
|
||||
pattern: 'solid',
|
||||
fgColor: { argb: 'FF4472C4' }
|
||||
};
|
||||
cell.alignment = { vertical: 'middle', horizontal: 'center' };
|
||||
});
|
||||
|
||||
// 添加数据
|
||||
data.forEach((item) => {
|
||||
worksheet.addRow(item);
|
||||
});
|
||||
|
||||
// 自动调整列宽
|
||||
worksheet.columns.forEach((column) => {
|
||||
if (!column.width) {
|
||||
const maxLength = Math.max(
|
||||
column.header.length,
|
||||
...worksheet.getColumn(column.key).values.map(v =>
|
||||
v ? String(v).length : 0
|
||||
)
|
||||
);
|
||||
column.width = Math.min(Math.max(maxLength + 2, 10), 50);
|
||||
}
|
||||
});
|
||||
|
||||
// 生成Excel文件Buffer
|
||||
const buffer = await workbook.xlsx.writeBuffer();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化日期
|
||||
* @param {Date|String} date - 日期
|
||||
* @returns {String} 格式化后的日期字符串
|
||||
*/
|
||||
static formatDate(date) {
|
||||
if (!date) return '';
|
||||
const d = new Date(date);
|
||||
const year = d.getFullYear();
|
||||
const month = String(d.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(d.getDate()).padStart(2, '0');
|
||||
const hours = String(d.getHours()).padStart(2, '0');
|
||||
const minutes = String(d.getMinutes()).padStart(2, '0');
|
||||
const seconds = String(d.getSeconds()).padStart(2, '0');
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化金额
|
||||
* @param {Number} amount - 金额
|
||||
* @returns {String} 格式化后的金额字符串
|
||||
*/
|
||||
static formatAmount(amount) {
|
||||
if (!amount && amount !== 0) return '';
|
||||
return `¥${Number(amount).toFixed(2)}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化状态
|
||||
* @param {String} status - 状态值
|
||||
* @param {Object} statusMap - 状态映射表
|
||||
* @returns {String} 状态文本
|
||||
*/
|
||||
static formatStatus(status, statusMap) {
|
||||
return statusMap[status] || status || '';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ExcelExport;
|
||||
|
||||
Reference in New Issue
Block a user