添加银行端后端接口
This commit is contained in:
468
bank-backend/controllers/loanApplicationController.js
Normal file
468
bank-backend/controllers/loanApplicationController.js
Normal file
@@ -0,0 +1,468 @@
|
||||
/**
|
||||
* 贷款申请控制器
|
||||
* @file loanApplicationController.js
|
||||
* @description 银行系统贷款申请相关API控制器
|
||||
*/
|
||||
const { LoanApplication, AuditRecord, User } = require('../models');
|
||||
const { Op } = require('sequelize');
|
||||
const { validationResult } = require('express-validator');
|
||||
|
||||
/**
|
||||
* 获取贷款申请列表
|
||||
* @param {Object} req - 请求对象
|
||||
* @param {Object} res - 响应对象
|
||||
*/
|
||||
const getApplications = async (req, res) => {
|
||||
try {
|
||||
const {
|
||||
page = 1,
|
||||
pageSize = 10,
|
||||
searchField = 'applicationNumber',
|
||||
searchValue = '',
|
||||
status = '',
|
||||
sortField = 'createdAt',
|
||||
sortOrder = 'DESC'
|
||||
} = req.query;
|
||||
|
||||
// 构建查询条件
|
||||
const where = {};
|
||||
|
||||
// 搜索条件
|
||||
if (searchValue) {
|
||||
if (searchField === 'applicationNumber') {
|
||||
where.applicationNumber = { [Op.like]: `%${searchValue}%` };
|
||||
} else if (searchField === 'customerName') {
|
||||
where[Op.or] = [
|
||||
{ borrowerName: { [Op.like]: `%${searchValue}%` } },
|
||||
{ farmerName: { [Op.like]: `%${searchValue}%` } }
|
||||
];
|
||||
} else if (searchField === 'productName') {
|
||||
where.productName = { [Op.like]: `%${searchValue}%` };
|
||||
}
|
||||
}
|
||||
|
||||
// 状态筛选
|
||||
if (status) {
|
||||
where.status = status;
|
||||
}
|
||||
|
||||
// 分页参数
|
||||
const offset = (parseInt(page) - 1) * parseInt(pageSize);
|
||||
const limit = parseInt(pageSize);
|
||||
|
||||
// 排序参数
|
||||
const order = [[sortField, sortOrder.toUpperCase()]];
|
||||
|
||||
// 查询数据
|
||||
const { count, rows } = await LoanApplication.findAndCountAll({
|
||||
where,
|
||||
include: [
|
||||
{
|
||||
model: User,
|
||||
as: 'applicant',
|
||||
attributes: ['id', 'username', 'real_name']
|
||||
},
|
||||
{
|
||||
model: User,
|
||||
as: 'approver',
|
||||
attributes: ['id', 'username', 'real_name']
|
||||
},
|
||||
{
|
||||
model: User,
|
||||
as: 'rejector',
|
||||
attributes: ['id', 'username', 'real_name']
|
||||
},
|
||||
{
|
||||
model: AuditRecord,
|
||||
as: 'auditRecords',
|
||||
include: [
|
||||
{
|
||||
model: User,
|
||||
as: 'auditorUser',
|
||||
attributes: ['id', 'username', 'real_name']
|
||||
}
|
||||
],
|
||||
order: [['auditTime', 'DESC']]
|
||||
}
|
||||
],
|
||||
order,
|
||||
offset,
|
||||
limit
|
||||
});
|
||||
|
||||
// 格式化数据
|
||||
const applications = rows.map(app => ({
|
||||
id: app.id,
|
||||
applicationNumber: app.applicationNumber,
|
||||
productName: app.productName,
|
||||
farmerName: app.farmerName,
|
||||
borrowerName: app.borrowerName,
|
||||
borrowerIdNumber: app.borrowerIdNumber,
|
||||
assetType: app.assetType,
|
||||
applicationQuantity: app.applicationQuantity,
|
||||
amount: parseFloat(app.amount),
|
||||
status: app.status,
|
||||
type: app.type,
|
||||
term: app.term,
|
||||
interestRate: parseFloat(app.interestRate),
|
||||
phone: app.phone,
|
||||
purpose: app.purpose,
|
||||
remark: app.remark,
|
||||
applicationTime: app.applicationTime,
|
||||
approvedTime: app.approvedTime,
|
||||
rejectedTime: app.rejectedTime,
|
||||
auditRecords: app.auditRecords.map(record => ({
|
||||
id: record.id,
|
||||
action: record.action,
|
||||
auditor: record.auditorUser?.real_name || record.auditor,
|
||||
auditorId: record.auditorId,
|
||||
comment: record.comment,
|
||||
time: record.auditTime,
|
||||
previousStatus: record.previousStatus,
|
||||
newStatus: record.newStatus
|
||||
}))
|
||||
}));
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
applications,
|
||||
pagination: {
|
||||
current: parseInt(page),
|
||||
pageSize: parseInt(pageSize),
|
||||
total: count,
|
||||
totalPages: Math.ceil(count / parseInt(pageSize))
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取贷款申请列表失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '获取贷款申请列表失败'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取贷款申请详情
|
||||
* @param {Object} req - 请求对象
|
||||
* @param {Object} res - 响应对象
|
||||
*/
|
||||
const getApplicationById = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
const application = await LoanApplication.findByPk(id, {
|
||||
include: [
|
||||
{
|
||||
model: User,
|
||||
as: 'applicant',
|
||||
attributes: ['id', 'username', 'real_name', 'email', 'phone']
|
||||
},
|
||||
{
|
||||
model: User,
|
||||
as: 'approver',
|
||||
attributes: ['id', 'username', 'real_name']
|
||||
},
|
||||
{
|
||||
model: User,
|
||||
as: 'rejector',
|
||||
attributes: ['id', 'username', 'real_name']
|
||||
},
|
||||
{
|
||||
model: AuditRecord,
|
||||
as: 'auditRecords',
|
||||
include: [
|
||||
{
|
||||
model: User,
|
||||
as: 'auditorUser',
|
||||
attributes: ['id', 'username', 'real_name']
|
||||
}
|
||||
],
|
||||
order: [['auditTime', 'DESC']]
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
if (!application) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '贷款申请不存在'
|
||||
});
|
||||
}
|
||||
|
||||
// 格式化数据
|
||||
const formattedApplication = {
|
||||
id: application.id,
|
||||
applicationNumber: application.applicationNumber,
|
||||
productName: application.productName,
|
||||
farmerName: application.farmerName,
|
||||
borrowerName: application.borrowerName,
|
||||
borrowerIdNumber: application.borrowerIdNumber,
|
||||
assetType: application.assetType,
|
||||
applicationQuantity: application.applicationQuantity,
|
||||
amount: parseFloat(application.amount),
|
||||
status: application.status,
|
||||
type: application.type,
|
||||
term: application.term,
|
||||
interestRate: parseFloat(application.interestRate),
|
||||
phone: application.phone,
|
||||
purpose: application.purpose,
|
||||
remark: application.remark,
|
||||
applicationTime: application.applicationTime,
|
||||
approvedTime: application.approvedTime,
|
||||
rejectedTime: application.rejectedTime,
|
||||
applicant: application.applicant,
|
||||
approver: application.approver,
|
||||
rejector: application.rejector,
|
||||
auditRecords: application.auditRecords.map(record => ({
|
||||
id: record.id,
|
||||
action: record.action,
|
||||
auditor: record.auditorUser?.real_name || record.auditor,
|
||||
auditorId: record.auditorId,
|
||||
comment: record.comment,
|
||||
time: record.auditTime,
|
||||
previousStatus: record.previousStatus,
|
||||
newStatus: record.newStatus
|
||||
}))
|
||||
};
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: formattedApplication
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取贷款申请详情失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '获取贷款申请详情失败'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 审核贷款申请
|
||||
* @param {Object} req - 请求对象
|
||||
* @param {Object} res - 响应对象
|
||||
*/
|
||||
const auditApplication = async (req, res) => {
|
||||
try {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '请求参数错误',
|
||||
errors: errors.array()
|
||||
});
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
const { action, comment } = req.body;
|
||||
const userId = req.user?.id;
|
||||
|
||||
// 获取申请信息
|
||||
const application = await LoanApplication.findByPk(id);
|
||||
if (!application) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '贷款申请不存在'
|
||||
});
|
||||
}
|
||||
|
||||
// 检查申请状态
|
||||
if (application.status === 'approved' || application.status === 'rejected') {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '该申请已完成审核,无法重复操作'
|
||||
});
|
||||
}
|
||||
|
||||
const previousStatus = application.status;
|
||||
let newStatus = application.status;
|
||||
|
||||
// 根据审核动作更新状态
|
||||
if (action === 'approve') {
|
||||
newStatus = 'approved';
|
||||
application.approvedTime = new Date();
|
||||
application.approvedBy = userId;
|
||||
} else if (action === 'reject') {
|
||||
newStatus = 'rejected';
|
||||
application.rejectedTime = new Date();
|
||||
application.rejectedBy = userId;
|
||||
application.rejectionReason = comment;
|
||||
}
|
||||
|
||||
// 更新申请状态
|
||||
application.status = newStatus;
|
||||
await application.save();
|
||||
|
||||
// 创建审核记录
|
||||
await AuditRecord.create({
|
||||
applicationId: id,
|
||||
action,
|
||||
auditor: req.user?.real_name || req.user?.username || '系统',
|
||||
auditorId: userId,
|
||||
comment,
|
||||
auditTime: new Date(),
|
||||
previousStatus,
|
||||
newStatus
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: action === 'approve' ? '审核通过' : '审核拒绝',
|
||||
data: {
|
||||
id: application.id,
|
||||
status: newStatus,
|
||||
action,
|
||||
comment
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('审核贷款申请失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '审核贷款申请失败'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取申请统计信息
|
||||
* @param {Object} req - 请求对象
|
||||
* @param {Object} res - 响应对象
|
||||
*/
|
||||
const getApplicationStats = async (req, res) => {
|
||||
try {
|
||||
const stats = await LoanApplication.findAll({
|
||||
attributes: [
|
||||
'status',
|
||||
[LoanApplication.sequelize.fn('COUNT', '*'), 'count'],
|
||||
[LoanApplication.sequelize.fn('SUM', LoanApplication.sequelize.col('amount')), 'totalAmount']
|
||||
],
|
||||
group: ['status'],
|
||||
raw: true
|
||||
});
|
||||
|
||||
const totalApplications = await LoanApplication.count();
|
||||
const totalAmount = await LoanApplication.sum('amount') || 0;
|
||||
|
||||
const statusStats = {
|
||||
pending_review: 0,
|
||||
verification_pending: 0,
|
||||
pending_binding: 0,
|
||||
approved: 0,
|
||||
rejected: 0
|
||||
};
|
||||
|
||||
const amountStats = {
|
||||
pending_review: 0,
|
||||
verification_pending: 0,
|
||||
pending_binding: 0,
|
||||
approved: 0,
|
||||
rejected: 0
|
||||
};
|
||||
|
||||
stats.forEach(stat => {
|
||||
statusStats[stat.status] = parseInt(stat.count);
|
||||
amountStats[stat.status] = parseFloat(stat.totalAmount) || 0;
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
total: {
|
||||
applications: totalApplications,
|
||||
amount: parseFloat(totalAmount)
|
||||
},
|
||||
byStatus: {
|
||||
counts: statusStats,
|
||||
amounts: amountStats
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取申请统计失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '获取申请统计失败'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量更新申请状态
|
||||
* @param {Object} req - 请求对象
|
||||
* @param {Object} res - 响应对象
|
||||
*/
|
||||
const batchUpdateStatus = async (req, res) => {
|
||||
try {
|
||||
const { ids, status } = req.body;
|
||||
const userId = req.user?.id;
|
||||
|
||||
if (!ids || !Array.isArray(ids) || ids.length === 0) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '请选择要操作的申请'
|
||||
});
|
||||
}
|
||||
|
||||
if (!status) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '请指定目标状态'
|
||||
});
|
||||
}
|
||||
|
||||
// 更新申请状态
|
||||
const [updatedCount] = await LoanApplication.update(
|
||||
{
|
||||
status,
|
||||
...(status === 'approved' && { approvedTime: new Date(), approvedBy: userId }),
|
||||
...(status === 'rejected' && { rejectedTime: new Date(), rejectedBy: userId })
|
||||
},
|
||||
{
|
||||
where: {
|
||||
id: { [Op.in]: ids }
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 为每个申请创建审核记录
|
||||
for (const id of ids) {
|
||||
await AuditRecord.create({
|
||||
applicationId: id,
|
||||
action: status === 'approved' ? 'approve' : 'reject',
|
||||
auditor: req.user?.real_name || req.user?.username || '系统',
|
||||
auditorId: userId,
|
||||
comment: `批量${status === 'approved' ? '通过' : '拒绝'}`,
|
||||
auditTime: new Date(),
|
||||
newStatus: status
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: `成功更新${updatedCount}个申请的状态`,
|
||||
data: {
|
||||
updatedCount,
|
||||
status
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('批量更新申请状态失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '批量更新申请状态失败'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getApplications,
|
||||
getApplicationById,
|
||||
auditApplication,
|
||||
getApplicationStats,
|
||||
batchUpdateStatus
|
||||
};
|
||||
Reference in New Issue
Block a user