Files
nxxmdata/bank-backend/controllers/loanContractController.js
2025-09-25 17:43:54 +08:00

451 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 贷款合同控制器
* @file loanContractController.js
* @description 银行系统贷款合同相关API控制器
*/
const { LoanContract, User } = require('../models');
const { Op } = require('sequelize');
const { validationResult } = require('express-validator');
/**
* 获取贷款合同列表
* @param {Object} req - 请求对象
* @param {Object} res - 响应对象
*/
const getContracts = async (req, res) => {
try {
const {
page = 1,
pageSize = 10,
searchField = 'contractNumber',
searchValue = '',
status = '',
sortField = 'createdAt',
sortOrder = 'DESC'
} = req.query;
// 构建查询条件
const where = {};
// 搜索条件
if (searchValue) {
if (searchField === 'contractNumber') {
where.contract_number = { [Op.like]: `%${searchValue}%` };
} else if (searchField === 'customerName') {
where.customer_name = { [Op.like]: `%${searchValue}%` };
} else if (searchField === 'customerPhone') {
where.customer_phone = { [Op.like]: `%${searchValue}%` };
} else if (searchField === 'customerIdCard') {
where.customer_id_card = { [Op.like]: `%${searchValue}%` };
} else if (searchField === 'applicationNumber') {
// 数据库中实际没有applicationNumber字段使用id作为替代
where.id = { [Op.like]: `%${searchValue}%` };
}
}
// 状态筛选
if (status) {
where.status = status;
}
// 分页参数
const offset = (parseInt(page) - 1) * parseInt(pageSize);
const limit = parseInt(pageSize);
// 排序参数 - 映射字段名
const fieldMapping = {
'createdAt': 'created_at',
'updatedAt': 'updated_at',
'contractDate': 'contract_date',
'loanAmount': 'loan_amount',
'loanTerm': 'loan_term',
'interestRate': 'interest_rate'
};
const dbSortField = fieldMapping[sortField] || sortField;
const order = [[dbSortField, sortOrder.toUpperCase()]];
// 查询数据
const { count, rows } = await LoanContract.findAndCountAll({
where,
order,
offset,
limit
});
// 格式化数据
const contracts = rows.map(contract => ({
id: contract.id,
contract_number: contract.contract_number,
customer_name: contract.customer_name,
customer_phone: contract.customer_phone,
customer_id_card: contract.customer_id_card,
loan_amount: parseFloat(contract.loan_amount),
loan_term: contract.loan_term,
interest_rate: parseFloat(contract.interest_rate),
contract_date: contract.contract_date,
status: contract.status,
created_at: contract.created_at,
updated_at: contract.updated_at
}));
res.json({
success: true,
data: {
contracts,
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 getContractById = async (req, res) => {
try {
const { id } = req.params;
const contract = await LoanContract.findByPk(id, {
include: [
{
model: User,
as: 'creator',
attributes: ['id', 'username', 'real_name', 'email', 'phone']
},
{
model: User,
as: 'updater',
attributes: ['id', 'username', 'real_name']
}
]
});
if (!contract) {
return res.status(404).json({
success: false,
message: '贷款合同不存在'
});
}
// 格式化数据
const formattedContract = {
id: contract.id,
contractNumber: contract.contractNumber,
applicationNumber: contract.applicationNumber,
productName: contract.productName,
farmerName: contract.farmerName,
borrowerName: contract.borrowerName,
borrowerIdNumber: contract.borrowerIdNumber,
assetType: contract.assetType,
applicationQuantity: contract.applicationQuantity,
amount: parseFloat(contract.amount),
paidAmount: parseFloat(contract.paidAmount),
status: contract.status,
type: contract.type,
term: contract.term,
interestRate: parseFloat(contract.interestRate),
phone: contract.phone,
purpose: contract.purpose,
remark: contract.remark,
contractTime: contract.contractTime,
disbursementTime: contract.disbursementTime,
maturityTime: contract.maturityTime,
completedTime: contract.completedTime,
remainingAmount: parseFloat(contract.amount - contract.paidAmount),
repaymentProgress: contract.getRepaymentProgress(),
creator: contract.creator,
updater: contract.updater
};
res.json({
success: true,
data: formattedContract
});
} catch (error) {
console.error('获取贷款合同详情失败:', error);
res.status(500).json({
success: false,
message: '获取贷款合同详情失败'
});
}
};
/**
* 创建贷款合同
* @param {Object} req - 请求对象
* @param {Object} res - 响应对象
*/
const createContract = async (req, res) => {
try {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
success: false,
message: '请求参数错误',
errors: errors.array()
});
}
const contractData = {
...req.body,
createdBy: req.user?.id
};
const contract = await LoanContract.create(contractData);
res.status(201).json({
success: true,
message: '贷款合同创建成功',
data: contract
});
} catch (error) {
console.error('创建贷款合同失败:', error);
res.status(500).json({
success: false,
message: '创建贷款合同失败'
});
}
};
/**
* 更新贷款合同
* @param {Object} req - 请求对象
* @param {Object} res - 响应对象
*/
const updateContract = 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 updateData = {
...req.body,
updatedBy: req.user?.id
};
const [updatedCount] = await LoanContract.update(updateData, {
where: { id }
});
if (updatedCount === 0) {
return res.status(404).json({
success: false,
message: '贷款合同不存在'
});
}
const updatedContract = await LoanContract.findByPk(id);
res.json({
success: true,
message: '贷款合同更新成功',
data: updatedContract
});
} catch (error) {
console.error('更新贷款合同失败:', error);
res.status(500).json({
success: false,
message: '更新贷款合同失败'
});
}
};
/**
* 删除贷款合同
* @param {Object} req - 请求对象
* @param {Object} res - 响应对象
*/
const deleteContract = async (req, res) => {
try {
const { id } = req.params;
const deletedCount = await LoanContract.destroy({
where: { id }
});
if (deletedCount === 0) {
return res.status(404).json({
success: false,
message: '贷款合同不存在'
});
}
res.json({
success: true,
message: '贷款合同删除成功'
});
} catch (error) {
console.error('删除贷款合同失败:', error);
res.status(500).json({
success: false,
message: '删除贷款合同失败'
});
}
};
/**
* 获取合同统计信息
* @param {Object} req - 请求对象
* @param {Object} res - 响应对象
*/
const getContractStats = async (req, res) => {
try {
const stats = await LoanContract.findAll({
attributes: [
'status',
[LoanContract.sequelize.fn('COUNT', '*'), 'count'],
[LoanContract.sequelize.fn('SUM', LoanContract.sequelize.col('amount')), 'totalAmount'],
[LoanContract.sequelize.fn('SUM', LoanContract.sequelize.col('paidAmount')), 'totalPaidAmount']
],
group: ['status'],
raw: true
});
const totalContracts = await LoanContract.count();
const totalAmount = await LoanContract.sum('amount') || 0;
const totalPaidAmount = await LoanContract.sum('paidAmount') || 0;
const statusStats = {
active: 0,
pending: 0,
completed: 0,
defaulted: 0,
cancelled: 0
};
const amountStats = {
active: 0,
pending: 0,
completed: 0,
defaulted: 0,
cancelled: 0
};
const paidAmountStats = {
active: 0,
pending: 0,
completed: 0,
defaulted: 0,
cancelled: 0
};
stats.forEach(stat => {
statusStats[stat.status] = parseInt(stat.count);
amountStats[stat.status] = parseFloat(stat.totalAmount) || 0;
paidAmountStats[stat.status] = parseFloat(stat.totalPaidAmount) || 0;
});
res.json({
success: true,
data: {
total: {
contracts: totalContracts,
amount: parseFloat(totalAmount),
paidAmount: parseFloat(totalPaidAmount),
remainingAmount: parseFloat(totalAmount - totalPaidAmount)
},
byStatus: {
counts: statusStats,
amounts: amountStats,
paidAmounts: paidAmountStats
}
}
});
} 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 updateData = {
status,
updatedBy: userId
};
// 根据状态设置相应的时间字段
if (status === 'active') {
updateData.disbursementTime = new Date();
} else if (status === 'completed') {
updateData.completedTime = new Date();
}
const [updatedCount] = await LoanContract.update(updateData, {
where: {
id: { [Op.in]: ids }
}
});
res.json({
success: true,
message: `成功更新${updatedCount}个合同的状态`,
data: {
updatedCount,
status
}
});
} catch (error) {
console.error('批量更新合同状态失败:', error);
res.status(500).json({
success: false,
message: '批量更新合同状态失败'
});
}
};
module.exports = {
getContracts,
getContractById,
createContract,
updateContract,
deleteContract,
getContractStats,
batchUpdateStatus
};