/** * 贷款合同控制器 * @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}%` }; } else if (searchField === 'borrowerName') { where.customer_name = { [Op.like]: `%${searchValue}%` }; } else if (searchField === 'farmerName') { where.customer_name = { [Op.like]: `%${searchValue}%` }; } else if (searchField === 'productName') { // 产品名称搜索暂时不处理,因为数据库中没有这个字段 // 可以在前端过滤 } } // 状态筛选 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, contractNumber: contract.contract_number, applicationNumber: `APP-${String(contract.id).padStart(6, '0')}`, // 生成申请单号 productName: '养殖贷款', // 默认产品名称 farmerName: contract.customer_name || '未知养殖户', borrowerName: contract.customer_name || '未知借款人', borrowerIdNumber: contract.customer_id_card || '', assetType: '养殖设备', // 默认生资种类 applicationQuantity: '1', // 默认申请数量 amount: parseFloat(contract.loan_amount), paidAmount: 0, // 默认已还款金额 status: contract.status, type: 'livestock_collateral', // 默认类型 term: contract.loan_term, interestRate: parseFloat(contract.interest_rate), phone: contract.customer_phone || '', purpose: '养殖经营', // 默认用途 remark: '', // 默认备注 contractTime: contract.contract_date, disbursementTime: null, maturityTime: null, completedTime: null, remainingAmount: parseFloat(contract.loan_amount), // 剩余金额等于贷款金额 repaymentProgress: 0, // 默认还款进度 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); if (!contract) { return res.status(404).json({ success: false, message: '贷款合同不存在' }); } // 格式化数据 - 使用数据库实际字段名 const formattedContract = { id: contract.id, contractNumber: contract.contract_number, applicationNumber: contract.application_number || '', productName: contract.product_name || '', farmerName: contract.farmer_name || contract.customer_name, borrowerName: contract.borrower_name || contract.customer_name, borrowerIdNumber: contract.borrower_id_number || contract.customer_id_card, assetType: contract.asset_type || '', applicationQuantity: contract.application_quantity || '', amount: parseFloat(contract.loan_amount), paidAmount: parseFloat(contract.paid_amount || 0), status: contract.status, type: contract.type || 'personal', term: contract.loan_term, interestRate: parseFloat(contract.interest_rate), phone: contract.customer_phone, purpose: contract.purpose || '', remark: contract.remark || '', contractTime: contract.contract_date, disbursementTime: contract.disbursement_time, maturityTime: contract.maturity_time, completedTime: contract.completed_time, remainingAmount: parseFloat(contract.loan_amount - (contract.paid_amount || 0)), repaymentProgress: contract.getRepaymentProgress ? contract.getRepaymentProgress() : 0 }; res.json({ success: true, data: formattedContract }); } catch (error) { console.error('获取贷款合同详情失败:', error); console.error('错误详情:', { message: error.message, stack: error.stack, name: error.name }); res.status(500).json({ success: false, message: '获取贷款合同详情失败', error: process.env.NODE_ENV === 'development' ? error.message : undefined }); } }; /** * 创建贷款合同 * @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 };