/** * 贷款合同控制器 * @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 };