完善保险端

This commit is contained in:
xuqiuyun
2025-10-11 08:59:57 +08:00
parent 9b8d177e34
commit 434fa135d1
8 changed files with 461 additions and 161 deletions

View File

@@ -87,8 +87,12 @@ const handleResponse = async (response) => {
try {
const contentType = response.headers.get('content-type')
// 处理Excel文件下载
if (contentType && contentType.includes('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')) {
// 处理文件下载Excel、CSV等
if (contentType && (
contentType.includes('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') ||
contentType.includes('text/csv') ||
contentType.includes('application/octet-stream')
)) {
data = await response.blob()
} else if (contentType && contentType.includes('application/json')) {
data = await response.json()

View File

@@ -643,10 +643,11 @@ const exportData = async () => {
const url = window.URL.createObjectURL(response.data)
const link = document.createElement('a')
link.href = url
link.setAttribute('download', `申请数据_${new Date().toISOString().slice(0, 10)}.xlsx`)
link.setAttribute('download', `保险申请数据_${new Date().toISOString().slice(0, 10)}.xlsx`)
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
window.URL.revokeObjectURL(url) // 释放内存
message.success('导出成功')
} catch (error) {
console.error('导出失败:', error)

View File

@@ -126,9 +126,9 @@
row-key="id"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'status'">
<a-tag :color="getStatusColor(record.status)">
{{ getStatusText(record.status) }}
<template v-if="column.key === 'taskStatus'">
<a-tag :color="getStatusColor(record.taskStatus)">
{{ getStatusText(record.taskStatus) }}
</a-tag>
</template>
<template v-else-if="column.key === 'priority'">
@@ -136,9 +136,6 @@
{{ getPriorityText(record.priority) }}
</a-tag>
</template>
<template v-else-if="column.key === 'duration'">
{{ record.duration }}
</template>
<template v-else-if="column.key === 'action'">
<a-space>
<a-button type="link" size="small" @click="handleView(record)">
@@ -182,11 +179,29 @@
>
<div v-if="selectedTask" class="task-detail">
<a-descriptions :column="2" bordered>
<a-descriptions-item label="任务名称">
{{ selectedTask.taskName }}
<a-descriptions-item label="申请单号">
{{ selectedTask.applicationNumber || '-' }}
</a-descriptions-item>
<a-descriptions-item label="任务编号">
{{ selectedTask.taskCode }}
<a-descriptions-item label="保单编号">
{{ selectedTask.policyNumber || '-' }}
</a-descriptions-item>
<a-descriptions-item label="产品名称">
{{ selectedTask.productName || '-' }}
</a-descriptions-item>
<a-descriptions-item label="保险期间">
{{ selectedTask.insurancePeriod || '-' }}
</a-descriptions-item>
<a-descriptions-item label="客户姓名">
{{ selectedTask.customerName || '-' }}
</a-descriptions-item>
<a-descriptions-item label="证件类型">
{{ selectedTask.idType || '-' }}
</a-descriptions-item>
<a-descriptions-item label="证件号码">
{{ selectedTask.idNumber || '-' }}
</a-descriptions-item>
<a-descriptions-item label="监管生资数量">
{{ selectedTask.supervisorySuppliesQuantity || '-' }}
</a-descriptions-item>
<a-descriptions-item label="优先级">
<a-tag :color="getPriorityColor(selectedTask.priority)">
@@ -194,27 +209,30 @@
</a-tag>
</a-descriptions-item>
<a-descriptions-item label="状态">
<a-tag :color="getStatusColor(selectedTask.status)">
{{ getStatusText(selectedTask.status) }}
<a-tag :color="getStatusColor(selectedTask.taskStatus)">
{{ getStatusText(selectedTask.taskStatus) }}
</a-tag>
</a-descriptions-item>
<a-descriptions-item label="负责人">
{{ selectedTask.assignedUser?.real_name || '-' }}
</a-descriptions-item>
<a-descriptions-item label="创建人">
{{ selectedTask.creator?.real_name || '-' }}
</a-descriptions-item>
<a-descriptions-item label="创建时间">
{{ selectedTask.createdAt }}
{{ selectedTask.createdAt || '-' }}
</a-descriptions-item>
<a-descriptions-item label="更新时间">
{{ selectedTask.updatedAt || '-' }}
</a-descriptions-item>
<a-descriptions-item label="完成时间">
{{ selectedTask.completedAt }}
</a-descriptions-item>
<a-descriptions-item label="负责人">
{{ selectedTask.assignee }}
{{ selectedTask.completedAt || '-' }}
</a-descriptions-item>
<a-descriptions-item label="处理时长">
{{ selectedTask.duration }}
{{ calculateDuration(selectedTask) }}
</a-descriptions-item>
<a-descriptions-item label="任务描述" :span="2">
{{ selectedTask.description }}
</a-descriptions-item>
<a-descriptions-item label="完成备注" :span="2">
{{ selectedTask.completionNotes }}
<a-descriptions-item label="备注" :span="2">
{{ selectedTask.notes || '-' }}
</a-descriptions-item>
</a-descriptions>
</div>
@@ -274,14 +292,14 @@ const pagination = reactive({
const columns = [
{
title: '任务编号',
dataIndex: 'taskCode',
key: 'taskCode',
dataIndex: 'applicationNumber',
key: 'applicationNumber',
width: 120
},
{
title: '任务名称',
dataIndex: 'taskName',
key: 'taskName',
dataIndex: 'productName',
key: 'productName',
ellipsis: true
},
{
@@ -292,27 +310,34 @@ const columns = [
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
dataIndex: 'taskStatus',
key: 'taskStatus',
width: 100
},
{
title: '负责人',
dataIndex: 'assignee',
key: 'assignee',
width: 120
width: 120,
customRender: ({ record }) => record.assignedUser?.real_name || '-'
},
{
title: '完成时间',
dataIndex: 'completedAt',
key: 'completedAt',
width: 150
width: 150,
customRender: ({ text }) => text || '-'
},
{
title: '处理时长',
dataIndex: 'duration',
key: 'duration',
width: 100
width: 100,
customRender: ({ record }) => {
if (!record.completedAt || !record.createdAt) return '-'
const created = new Date(record.createdAt)
const completed = new Date(record.completedAt)
const days = Math.ceil((completed - created) / (1000 * 60 * 60 * 24))
return `${days}`
}
},
{
title: '操作',
@@ -325,17 +350,31 @@ const columns = [
// 获取状态颜色
const getStatusColor = (status) => {
const colorMap = {
completed: 'green',
archived: 'purple'
'待处理': 'orange',
'处理中': 'blue',
'已完成': 'green',
'已取消': 'red',
'已归档': 'purple',
// 英文兼容
'completed': 'green',
'archived': 'purple'
}
return colorMap[status] || 'default'
}
// 获取状态文本
const getStatusText = (status) => {
// 如果已经是中文,直接返回
if (['待处理', '处理中', '已完成', '已取消', '已归档'].includes(status)) {
return status
}
// 英文转中文
const textMap = {
completed: '已完成',
archived: '已归档'
'pending': '待处理',
'processing': '处理中',
'completed': '已完成',
'rejected': '已取消',
'archived': '已归档'
}
return textMap[status] || status
}
@@ -343,23 +382,48 @@ const getStatusText = (status) => {
// 获取优先级颜色
const getPriorityColor = (priority) => {
const colorMap = {
high: 'red',
medium: 'orange',
low: 'blue'
'低': 'blue',
'中': 'green',
'高': 'orange',
'紧急': 'red',
// 英文兼容
'low': 'blue',
'medium': 'green',
'high': 'orange',
'urgent': 'red'
}
return colorMap[priority] || 'default'
}
// 获取优先级文本
const getPriorityText = (priority) => {
// 如果已经是中文,直接返回
if (['低', '中', '高', '紧急'].includes(priority)) {
return priority
}
// 英文转中文
const textMap = {
high: '',
medium: '中',
low: ''
'low': '',
'medium': '中',
'high': '',
'urgent': '紧急'
}
return textMap[priority] || priority
}
// 计算处理时长
const calculateDuration = (task) => {
if (!task.completedAt || !task.createdAt) return '-'
try {
const created = new Date(task.createdAt)
const completed = new Date(task.completedAt)
const days = Math.ceil((completed - created) / (1000 * 60 * 60 * 24))
return `${days}`
} catch (error) {
return '-'
}
}
// 搜索处理
const handleSearch = () => {
pagination.current = 1
@@ -520,12 +584,20 @@ const fetchTaskList = async () => {
const fetchStats = async () => {
try {
const response = await supervisionTaskApi.getStats()
console.log('统计数据响应:', response)
if (response.data && response.data.status === 'success') {
const statsData = response.data.data
stats.total = statsData.total || 0
stats.thisMonth = statsData.thisMonth || 0
stats.archived = statsData.archived || 0
stats.avgDuration = statsData.avgDuration || 0
// 从statusStats中获取已完成任务数
const statusStats = statsData.statusStats || []
const completedStat = statusStats.find(s => s.status === '已完成')
stats.total = completedStat ? completedStat.count : 0
// 这些数据暂时从总数获取后续可以从API补充
stats.thisMonth = 0
stats.archived = 0
stats.avgDuration = 0
}
} catch (error) {
console.error('获取统计数据失败:', error)

View File

@@ -315,9 +315,10 @@ const getInsuranceCategories = async (req, res) => {
// 导出保险申请数据
const exportApplications = async (req, res) => {
try {
const ExcelJS = require('exceljs');
const {
page = 1,
limit = 1000,
limit = 10000, // 增加导出数量限制
applicantName,
insuranceType,
insuranceCategory,
@@ -344,13 +345,15 @@ const exportApplications = async (req, res) => {
include: [
{
model: InsuranceType,
as: 'insuranceTypeInfo',
attributes: ['name', 'description']
as: 'insurance_type',
attributes: ['id', 'name', 'description'],
required: false
},
{
model: User,
as: 'createdByUser',
attributes: ['username', 'real_name']
as: 'reviewer',
attributes: ['id', 'username', 'real_name'],
required: false
}
],
order: [['created_at', 'DESC']],
@@ -358,38 +361,101 @@ const exportApplications = async (req, res) => {
offset: (parseInt(page) - 1) * parseInt(limit)
});
// 简单的CSV格式导出
const csvHeader = '申请编号,申请人姓名,身份证号,联系电话,参保类型,保险类型,保险金额,保险期限,地址,状态,申请时间,备注\n';
const csvData = applications.map(app => {
const statusMap = {
'pending': '待审核',
'initial_approved': '初审通过',
'under_review': '复审中',
'approved': '已通过',
'rejected': '已拒绝'
};
return [
app.application_number || '',
app.applicant_name || '',
app.id_card || '',
app.phone || '',
app.insurance_category || '',
app.insurance_type || '',
app.insurance_amount || '',
app.insurance_period || '',
app.address || '',
statusMap[app.status] || app.status,
app.created_at ? new Date(app.created_at).toLocaleString('zh-CN') : '',
app.remarks || ''
].map(field => `"${String(field).replace(/"/g, '""')}"`).join(',');
}).join('\n');
// 将Sequelize实例转换为纯对象
const plainApplications = applications.map(app => app.toJSON());
const csvContent = csvHeader + csvData;
// 创建Excel工作簿
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet('保险申请列表');
// 状态映射
const statusMap = {
'pending': '待审核',
'initial_approved': '初审通过',
'under_review': '复审中',
'approved': '已通过',
'rejected': '已拒绝'
};
// 定义列(包含所有字段)
worksheet.columns = [
{ header: 'ID', key: 'id', width: 8 },
{ header: '申请编号', key: 'application_no', width: 18 },
{ header: '客户姓名', key: 'customer_name', width: 12 },
{ header: '身份证号', key: 'customer_id_card', width: 20 },
{ header: '联系电话', key: 'customer_phone', width: 15 },
{ header: '客户地址', key: 'customer_address', width: 30 },
{ header: '参保类型', key: 'insurance_category', width: 12 },
{ header: '保险类型ID', key: 'insurance_type_id', width: 12 },
{ header: '保险类型名称', key: 'insurance_type_name', width: 15 },
{ header: '保险类型说明', key: 'insurance_type_description', width: 25 },
{ header: '申请数量', key: 'application_quantity', width: 12 },
{ header: '申请金额', key: 'application_amount', width: 15 },
{ header: '申请日期', key: 'application_date', width: 20 },
{ header: '状态', key: 'status', width: 12 },
{ header: '审核人ID', key: 'reviewer_id', width: 10 },
{ header: '审核人姓名', key: 'reviewer_name', width: 12 },
{ header: '审核日期', key: 'review_date', width: 20 },
{ header: '审核意见', key: 'review_notes', width: 30 },
{ header: '文档附件', key: 'documents', width: 30 },
{ header: '备注', key: 'remarks', width: 30 },
{ header: '创建时间', key: 'createdAt', width: 20 },
{ header: '更新时间', key: 'updatedAt', width: 20 }
];
// 设置表头样式
worksheet.getRow(1).font = { bold: true, size: 12 };
worksheet.getRow(1).fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FFE0E0E0' }
};
worksheet.getRow(1).alignment = { vertical: 'middle', horizontal: 'center' };
// 添加数据行
plainApplications.forEach(app => {
worksheet.addRow({
id: app.id || '',
application_no: app.application_no || '',
customer_name: app.customer_name || '',
customer_id_card: app.customer_id_card || '',
customer_phone: app.customer_phone || '',
customer_address: app.customer_address || '',
insurance_category: app.insurance_category || '',
insurance_type_id: app.insurance_type_id || '',
insurance_type_name: app.insurance_type?.name || '',
insurance_type_description: app.insurance_type?.description || '',
application_quantity: app.application_quantity || '',
application_amount: app.application_amount || '',
application_date: app.application_date || '',
status: statusMap[app.status] || app.status || '',
reviewer_id: app.reviewer_id || '',
reviewer_name: app.reviewer?.real_name || '',
review_date: app.review_date || '',
review_notes: app.review_notes || '',
documents: app.documents || '',
remarks: app.remarks || '',
createdAt: app.createdAt || '',
updatedAt: app.updatedAt || ''
});
});
// 设置数据行样式
worksheet.eachRow((row, rowNumber) => {
if (rowNumber > 1) {
row.alignment = { vertical: 'middle', horizontal: 'left' };
}
});
// 生成Excel文件
const buffer = await workbook.xlsx.writeBuffer();
// 设置响应头
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
res.setHeader('Content-Disposition', `attachment; filename="insurance_applications_${new Date().toISOString().slice(0, 10)}.xlsx"`);
res.setHeader('Content-Type', 'text/csv; charset=utf-8');
res.setHeader('Content-Disposition', `attachment; filename="insurance_applications_${new Date().toISOString().slice(0, 10)}.csv"`);
res.send('\uFEFF' + csvContent); // 添加BOM以支持中文
// 发送文件
res.send(buffer);
} catch (error) {
console.error('导出保险申请数据错误:', error);
res.status(500).json(responseFormat.error('导出保险申请数据失败'));

View File

@@ -544,59 +544,144 @@ const deleteLivestockClaim = async (req, res) => {
// 导出理赔列表到Excel
const exportToExcel = async (req, res) => {
try {
const { claim_number, claimant_name, status } = req.query;
const ExcelJS = require('exceljs');
const { claim_no, reporter_name, claim_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;
if (claim_no) where.claim_no = { [Op.like]: `%${claim_no}%` };
if (reporter_name) where.reporter_name = { [Op.like]: `%${reporter_name}%` };
if (claim_status) where.claim_status = claim_status;
const claims = await LivestockClaim.findAll({
where,
include: [{
model: LivestockPolicy,
as: 'policy',
attributes: ['policy_number']
}],
order: [['createdAt', 'DESC']],
raw: true,
nest: true
include: [
{
model: LivestockPolicy,
as: 'policy',
attributes: ['id', 'policy_no', 'policyholder_name'],
required: false
},
{
model: User,
as: 'reviewer',
attributes: ['id', 'real_name', 'username'],
required: false
},
{
model: User,
as: 'creator',
attributes: ['id', 'real_name', 'username'],
required: false
}
],
order: [['created_at', 'DESC']],
limit: 10000
});
const statusMap = { pending: '待审核', approved: '已批准', rejected: '已拒绝', settled: '已理赔' };
// 将Sequelize实例转换为纯对象
const plainClaims = claims.map(claim => claim.toJSON());
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 statusMap = {
'pending': '待审核',
'investigating': '调查中',
'approved': '已批准',
'rejected': '已拒绝',
'paid': '已支付'
};
const columns = [
{ header: '理赔编号', key: 'claim_number', width: 20 },
{ header: '保单编号', key: 'policy_number', width: 20 },
{ header: '理赔人', key: 'claimant_name', width: 15 },
// 理赔类型映射
const claimTypeMap = {
'death': '死亡',
'disease': '疾病',
'accident': '意外事故',
'natural_disaster': '自然灾害'
};
// 创建Excel工作簿
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet('生资理赔列表');
// 定义列(包含所有字段)
worksheet.columns = [
{ header: 'ID', key: 'id', width: 8 },
{ header: '理赔编号', key: 'claim_no', width: 18 },
{ header: '报案人姓名', key: 'reporter_name', width: 12 },
{ header: '联系电话', key: 'contact_phone', width: 15 },
{ header: '保单号', key: 'policy_no', width: 18 },
{ header: '保单持有人', key: 'policy_holder', width: 12 },
{ header: '理赔类型', key: 'claim_type', width: 12 },
{ header: '受影响数量', key: 'affected_count', width: 12 },
{ 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 }
{ header: '事故日期', key: 'incident_date', width: 20 },
{ header: '报案日期', key: 'report_date', width: 20 },
{ header: '事故描述', key: 'incident_description', width: 35 },
{ header: '事故地点', key: 'incident_location', width: 25 },
{ header: '理赔状态', key: 'claim_status', width: 12 },
{ header: '调查报告', key: 'investigation_report', width: 30 },
{ header: '审核人', key: 'reviewer_name', width: 12 },
{ header: '审核备注', key: 'review_notes', width: 30 },
{ header: '审核日期', key: 'review_date', width: 20 },
{ header: '赔付日期', key: 'payment_date', width: 20 },
{ header: '赔付金额', key: 'payment_amount', width: 15 },
{ header: '创建人', key: 'creator_name', width: 12 },
{ header: '创建时间', key: 'created_at', width: 20 },
{ header: '更新时间', key: 'updated_at', width: 20 }
];
const buffer = await ExcelExport.exportToExcel(exportData, columns, '理赔列表');
// 设置表头样式
worksheet.getRow(1).font = { bold: true, size: 12 };
worksheet.getRow(1).fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FFE0E0E0' }
};
worksheet.getRow(1).alignment = { vertical: 'middle', horizontal: 'center' };
// 添加数据行
plainClaims.forEach(claim => {
worksheet.addRow({
id: claim.id || '',
claim_no: claim.claim_no || '',
reporter_name: claim.reporter_name || '',
contact_phone: claim.contact_phone || '',
policy_no: claim.policy_no || '',
policy_holder: claim.policy?.policyholder_name || '',
claim_type: claimTypeMap[claim.claim_type] || claim.claim_type || '',
affected_count: claim.affected_count || '',
claim_amount: claim.claim_amount || '',
incident_date: claim.incident_date || '',
report_date: claim.report_date || '',
incident_description: claim.incident_description || '',
incident_location: claim.incident_location || '',
claim_status: statusMap[claim.claim_status] || claim.claim_status || '',
investigation_report: claim.investigation_report || '',
reviewer_name: claim.reviewer?.real_name || '',
review_notes: claim.review_notes || '',
review_date: claim.review_date || '',
payment_date: claim.payment_date || '',
payment_amount: claim.payment_amount || '',
creator_name: claim.creator?.real_name || '',
created_at: claim.created_at || '',
updated_at: claim.updated_at || ''
});
});
// 设置数据行样式
worksheet.eachRow((row, rowNumber) => {
if (rowNumber > 1) {
row.alignment = { vertical: 'middle', horizontal: 'left' };
}
});
// 生成Excel文件
const buffer = await workbook.xlsx.writeBuffer();
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);
console.error('导出生资理赔记录失败:', error);
res.status(500).json(responseFormat.error('导出失败'));
}
};

View File

@@ -367,6 +367,7 @@ const deletePolicy = async (req, res) => {
// 导出保单列表到Excel
const exportToExcel = async (req, res) => {
try {
const ExcelJS = require('exceljs');
const { policy_number, policyholder_name, status } = req.query;
const where = {};
@@ -378,41 +379,94 @@ const exportToExcel = async (req, res) => {
where,
include: [{
model: InsuranceType,
as: 'InsuranceType',
attributes: ['name']
as: 'insurance_type', // 修正:使用正确的关联别名
attributes: ['id', 'name', 'description'],
required: false
}],
order: [['created_at', 'DESC']],
raw: true,
nest: true
limit: 10000
});
const statusMap = { active: '生效中', pending: '待生效', expired: '已过期', cancelled: '已取消' };
// 将Sequelize实例转换为纯对象
const plainPolicies = policies.map(policy => policy.toJSON());
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 statusMap = {
'active': '生效中',
'pending': '待生效',
'expired': '已过期',
'cancelled': '已取消'
};
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 },
// 创建Excel工作簿
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet('保单列表');
// 定义列(包含所有字段)
worksheet.columns = [
{ header: 'ID', key: 'id', width: 8 },
{ header: '保单编号', key: 'policy_number', width: 18 },
{ header: '投保人姓名', key: 'policyholder_name', width: 15 },
{ header: '被保人姓名', key: 'insured_name', width: 15 },
{ header: '保险类型ID', key: 'insurance_type_id', width: 12 },
{ header: '保险类型名称', key: 'insurance_type_name', width: 18 },
{ header: '保险类型说明', key: 'insurance_type_description', width: 25 },
{ header: '保障金额', key: 'coverage_amount', width: 15 },
{ header: '保费金额', key: 'premium_amount', width: 15 },
{ header: '开始日期', key: 'start_date', width: 20 },
{ header: '结束日期', key: 'end_date', width: 20 },
{ header: '状态', key: 'status', width: 12 },
{ header: '创建时间', key: 'created_at', width: 20 }
{ header: '联系电话', key: 'phone', width: 15 },
{ header: '电子邮箱', key: 'email', width: 25 },
{ header: '地址', key: 'address', width: 30 },
{ header: '备注', key: 'remarks', width: 30 },
{ header: '创建时间', key: 'created_at', width: 20 },
{ header: '更新时间', key: 'updated_at', width: 20 }
];
const buffer = await ExcelExport.exportToExcel(exportData, columns, '保单列表');
// 设置表头样式
worksheet.getRow(1).font = { bold: true, size: 12 };
worksheet.getRow(1).fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FFE0E0E0' }
};
worksheet.getRow(1).alignment = { vertical: 'middle', horizontal: 'center' };
// 添加数据行
plainPolicies.forEach(policy => {
worksheet.addRow({
id: policy.id || '',
policy_number: policy.policy_no || '', // 修正:使用 policy_no
policyholder_name: policy.policyholder_name || '',
insured_name: policy.insured_name || '',
insurance_type_id: policy.insurance_type_id || '',
insurance_type_name: policy.insurance_type?.name || '',
insurance_type_description: policy.insurance_type?.description || '',
coverage_amount: policy.coverage_amount || '',
premium_amount: policy.premium_amount || '',
start_date: policy.start_date || '',
end_date: policy.end_date || '',
status: statusMap[policy.policy_status] || policy.policy_status || '', // 修正:使用 policy_status
phone: policy.phone || '',
email: policy.email || '',
address: policy.address || '',
remarks: policy.remarks || '',
created_at: policy.created_at || '',
updated_at: policy.updated_at || ''
});
});
// 设置数据行样式
worksheet.eachRow((row, rowNumber) => {
if (rowNumber > 1) {
row.alignment = { vertical: 'middle', horizontal: 'left' };
}
});
// 生成Excel文件
const buffer = await workbook.xlsx.writeBuffer();
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
res.setHeader('Content-Disposition', `attachment; filename=policies_${Date.now()}.xlsx`);
res.send(buffer);

View File

@@ -24,6 +24,22 @@ class SupervisoryTaskController {
sortOrder = 'DESC'
} = req.query;
// 状态映射:英文到中文
const statusMap = {
'pending': '待处理',
'processing': '处理中',
'completed': '已完成',
'rejected': '已取消'
};
// 优先级映射:英文到中文
const priorityMap = {
'low': '低',
'medium': '中',
'high': '高',
'urgent': '紧急'
};
// 构建查询条件
const where = {};
@@ -36,11 +52,13 @@ class SupervisoryTaskController {
}
if (taskStatus) {
where.taskStatus = taskStatus;
// 如果传入的是英文状态,转换为中文
where.taskStatus = statusMap[taskStatus] || taskStatus;
}
if (priority) {
where.priority = priority;
// 如果传入的是英文优先级,转换为中文
where.priority = priorityMap[priority] || priority;
}
// 日期范围筛选

View File

@@ -8,6 +8,16 @@ router.get('/applications', jwtAuth, checkPermission('insurance', 'read'),
insuranceController.getApplications
);
// 获取保险申请统计(必须在 :id 路由之前)
router.get('/applications-stats', jwtAuth, checkPermission('insurance', 'read'),
insuranceController.getApplicationStats
);
// 导出保险申请数据(必须在 :id 路由之前)
router.get('/applications/export', jwtAuth, checkPermission('insurance', 'read'),
insuranceController.exportApplications
);
// 创建保险申请
router.post('/applications', jwtAuth, checkPermission('insurance', 'create'),
insuranceController.createApplication
@@ -33,16 +43,6 @@ router.delete('/applications/:id', jwtAuth, checkPermission('insurance', 'delete
insuranceController.deleteApplication
);
// 获取保险申请统计
router.get('/applications-stats', jwtAuth, checkPermission('insurance', 'read'),
insuranceController.getApplicationStats
);
// 导出保险申请数据
router.get('/applications/export', jwtAuth, checkPermission('insurance', 'read'),
insuranceController.exportApplications
);
// 获取参保类型选项
router.get('/categories', jwtAuth, checkPermission('insurance', 'read'),
insuranceController.getInsuranceCategories