546 lines
13 KiB
JavaScript
546 lines
13 KiB
JavaScript
|
|
/**
|
||
|
|
* 贷款解押控制器
|
||
|
|
* @file loanReleaseController.js
|
||
|
|
* @description 银行系统贷款解押相关接口控制器
|
||
|
|
*/
|
||
|
|
const { LoanRelease, LoanReleaseHistory, User } = require('../models');
|
||
|
|
const { Op } = require('sequelize');
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 获取解押申请列表
|
||
|
|
* @param {Object} req - 请求对象
|
||
|
|
* @param {Object} res - 响应对象
|
||
|
|
*/
|
||
|
|
const getReleases = async (req, res) => {
|
||
|
|
try {
|
||
|
|
const {
|
||
|
|
page = 1,
|
||
|
|
pageSize = 10,
|
||
|
|
searchField = 'application_number',
|
||
|
|
searchValue = '',
|
||
|
|
status = '',
|
||
|
|
sortField = 'created_at',
|
||
|
|
sortOrder = 'DESC'
|
||
|
|
} = req.query;
|
||
|
|
|
||
|
|
// 构建查询条件
|
||
|
|
const whereCondition = {};
|
||
|
|
|
||
|
|
// 搜索条件
|
||
|
|
if (searchValue) {
|
||
|
|
switch (searchField) {
|
||
|
|
case 'application_number':
|
||
|
|
whereCondition.application_number = {
|
||
|
|
[Op.like]: `%${searchValue}%`
|
||
|
|
};
|
||
|
|
break;
|
||
|
|
case 'customer_name':
|
||
|
|
whereCondition[Op.or] = [
|
||
|
|
{ customer_name: { [Op.like]: `%${searchValue}%` } },
|
||
|
|
{ farmer_name: { [Op.like]: `%${searchValue}%` } }
|
||
|
|
];
|
||
|
|
break;
|
||
|
|
case 'product_name':
|
||
|
|
whereCondition.product_name = {
|
||
|
|
[Op.like]: `%${searchValue}%`
|
||
|
|
};
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 状态筛选
|
||
|
|
if (status) {
|
||
|
|
whereCondition.status = status;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 分页参数
|
||
|
|
const offset = (page - 1) * pageSize;
|
||
|
|
const limit = parseInt(pageSize);
|
||
|
|
|
||
|
|
// 查询数据
|
||
|
|
const { count, rows } = await LoanRelease.findAndCountAll({
|
||
|
|
where: whereCondition,
|
||
|
|
order: [[sortField, sortOrder.toUpperCase()]],
|
||
|
|
offset,
|
||
|
|
limit,
|
||
|
|
include: [
|
||
|
|
{
|
||
|
|
model: User,
|
||
|
|
as: 'processor',
|
||
|
|
attributes: ['id', 'username', 'real_name']
|
||
|
|
}
|
||
|
|
]
|
||
|
|
});
|
||
|
|
|
||
|
|
// 格式化返回数据
|
||
|
|
const releases = rows.map(release => ({
|
||
|
|
id: release.id,
|
||
|
|
applicationNumber: release.application_number,
|
||
|
|
productName: release.product_name || '养殖贷款',
|
||
|
|
farmerName: release.farmer_name || release.customer_name,
|
||
|
|
applicantName: release.customer_name,
|
||
|
|
applicantIdNumber: release.customer_id_card,
|
||
|
|
applicantPhone: release.customer_phone,
|
||
|
|
assetType: release.collateral_type === 'livestock' ? '牛' : '其他',
|
||
|
|
releaseQuantity: release.release_quantity || '1头',
|
||
|
|
releaseAmount: parseFloat(release.release_amount),
|
||
|
|
status: release.status,
|
||
|
|
applicationTime: release.application_date,
|
||
|
|
processTime: release.process_date,
|
||
|
|
completeTime: release.complete_date,
|
||
|
|
processorName: release.processor?.real_name || release.processor_name,
|
||
|
|
processComment: release.process_comment,
|
||
|
|
rejectionReason: release.rejection_reason,
|
||
|
|
remark: release.remark,
|
||
|
|
created_at: release.created_at,
|
||
|
|
updated_at: release.updated_at
|
||
|
|
}));
|
||
|
|
|
||
|
|
res.json({
|
||
|
|
success: true,
|
||
|
|
data: {
|
||
|
|
releases,
|
||
|
|
pagination: {
|
||
|
|
current: parseInt(page),
|
||
|
|
pageSize: limit,
|
||
|
|
total: count,
|
||
|
|
totalPages: Math.ceil(count / limit)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
} catch (error) {
|
||
|
|
console.error('获取解押申请列表失败:', error);
|
||
|
|
res.status(500).json({
|
||
|
|
success: false,
|
||
|
|
message: '获取解押申请列表失败'
|
||
|
|
});
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 获取解押申请详情
|
||
|
|
* @param {Object} req - 请求对象
|
||
|
|
* @param {Object} res - 响应对象
|
||
|
|
*/
|
||
|
|
const getReleaseDetail = async (req, res) => {
|
||
|
|
try {
|
||
|
|
const { id } = req.params;
|
||
|
|
|
||
|
|
const release = await LoanRelease.findByPk(id, {
|
||
|
|
include: [
|
||
|
|
{
|
||
|
|
model: User,
|
||
|
|
as: 'processor',
|
||
|
|
attributes: ['id', 'username', 'real_name']
|
||
|
|
}
|
||
|
|
]
|
||
|
|
});
|
||
|
|
|
||
|
|
if (!release) {
|
||
|
|
return res.status(404).json({
|
||
|
|
success: false,
|
||
|
|
message: '解押申请不存在'
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// 获取历史记录
|
||
|
|
const history = await LoanReleaseHistory.findAll({
|
||
|
|
where: { release_id: id },
|
||
|
|
order: [['operation_time', 'ASC']]
|
||
|
|
});
|
||
|
|
|
||
|
|
const releaseDetail = {
|
||
|
|
id: release.id,
|
||
|
|
releaseNumber: release.application_number,
|
||
|
|
customerName: release.customer_name,
|
||
|
|
contractNumber: `CONTRACT-${String(release.contract_id || release.id).padStart(6, '0')}`,
|
||
|
|
status: release.status,
|
||
|
|
collateralType: release.collateral_type,
|
||
|
|
collateralDescription: release.collateral_description,
|
||
|
|
loanAmount: parseFloat(release.loan_amount || 0),
|
||
|
|
collateralValue: parseFloat(release.collateral_value || 0),
|
||
|
|
applicationTime: release.application_date,
|
||
|
|
processTime: release.process_date,
|
||
|
|
completeTime: release.complete_date,
|
||
|
|
phone: release.customer_phone,
|
||
|
|
idCard: release.customer_id_card,
|
||
|
|
reason: release.application_reason,
|
||
|
|
remark: release.remark,
|
||
|
|
history: history.map(h => ({
|
||
|
|
id: h.id,
|
||
|
|
action: h.action,
|
||
|
|
operator: h.operator,
|
||
|
|
time: h.operation_time,
|
||
|
|
comment: h.comment
|
||
|
|
}))
|
||
|
|
};
|
||
|
|
|
||
|
|
res.json({
|
||
|
|
success: true,
|
||
|
|
data: releaseDetail
|
||
|
|
});
|
||
|
|
|
||
|
|
} catch (error) {
|
||
|
|
console.error('获取解押申请详情失败:', error);
|
||
|
|
res.status(500).json({
|
||
|
|
success: false,
|
||
|
|
message: '获取解押申请详情失败'
|
||
|
|
});
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 创建解押申请
|
||
|
|
* @param {Object} req - 请求对象
|
||
|
|
* @param {Object} res - 响应对象
|
||
|
|
*/
|
||
|
|
const createRelease = async (req, res) => {
|
||
|
|
try {
|
||
|
|
const {
|
||
|
|
contract_id,
|
||
|
|
customer_name,
|
||
|
|
customer_phone,
|
||
|
|
customer_id_card,
|
||
|
|
farmer_name,
|
||
|
|
product_name,
|
||
|
|
collateral_type,
|
||
|
|
collateral_description,
|
||
|
|
collateral_value,
|
||
|
|
loan_amount,
|
||
|
|
release_amount,
|
||
|
|
release_quantity,
|
||
|
|
application_reason,
|
||
|
|
remark
|
||
|
|
} = req.body;
|
||
|
|
|
||
|
|
// 生成申请单号
|
||
|
|
const applicationNumber = `REL-${Date.now()}`;
|
||
|
|
|
||
|
|
const release = await LoanRelease.create({
|
||
|
|
application_number: applicationNumber,
|
||
|
|
contract_id,
|
||
|
|
customer_name,
|
||
|
|
customer_phone,
|
||
|
|
customer_id_card,
|
||
|
|
farmer_name,
|
||
|
|
product_name,
|
||
|
|
collateral_type,
|
||
|
|
collateral_description,
|
||
|
|
collateral_value,
|
||
|
|
loan_amount,
|
||
|
|
release_amount,
|
||
|
|
release_quantity,
|
||
|
|
application_reason,
|
||
|
|
remark,
|
||
|
|
status: 'pending'
|
||
|
|
});
|
||
|
|
|
||
|
|
// 创建历史记录
|
||
|
|
await LoanReleaseHistory.create({
|
||
|
|
release_id: release.id,
|
||
|
|
action: 'apply',
|
||
|
|
operator: customer_name,
|
||
|
|
comment: '提交解押申请'
|
||
|
|
});
|
||
|
|
|
||
|
|
res.status(201).json({
|
||
|
|
success: true,
|
||
|
|
message: '解押申请创建成功',
|
||
|
|
data: {
|
||
|
|
id: release.id,
|
||
|
|
applicationNumber: release.application_number
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
} catch (error) {
|
||
|
|
console.error('创建解押申请失败:', error);
|
||
|
|
res.status(500).json({
|
||
|
|
success: false,
|
||
|
|
message: '创建解押申请失败'
|
||
|
|
});
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 更新解押申请
|
||
|
|
* @param {Object} req - 请求对象
|
||
|
|
* @param {Object} res - 响应对象
|
||
|
|
*/
|
||
|
|
const updateRelease = async (req, res) => {
|
||
|
|
try {
|
||
|
|
const { id } = req.params;
|
||
|
|
const updateData = req.body;
|
||
|
|
|
||
|
|
const release = await LoanRelease.findByPk(id);
|
||
|
|
if (!release) {
|
||
|
|
return res.status(404).json({
|
||
|
|
success: false,
|
||
|
|
message: '解押申请不存在'
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// 更新数据
|
||
|
|
await release.update(updateData);
|
||
|
|
|
||
|
|
res.json({
|
||
|
|
success: true,
|
||
|
|
message: '解押申请更新成功'
|
||
|
|
});
|
||
|
|
|
||
|
|
} catch (error) {
|
||
|
|
console.error('更新解押申请失败:', error);
|
||
|
|
res.status(500).json({
|
||
|
|
success: false,
|
||
|
|
message: '更新解押申请失败'
|
||
|
|
});
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 处理解押申请
|
||
|
|
* @param {Object} req - 请求对象
|
||
|
|
* @param {Object} res - 响应对象
|
||
|
|
*/
|
||
|
|
const processRelease = async (req, res) => {
|
||
|
|
try {
|
||
|
|
const { id } = req.params;
|
||
|
|
const { action, comment, remark } = req.body;
|
||
|
|
|
||
|
|
if (!req.user || !req.user.userId) {
|
||
|
|
return res.status(401).json({
|
||
|
|
success: false,
|
||
|
|
message: '用户信息无效'
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
const release = await LoanRelease.findByPk(id);
|
||
|
|
if (!release) {
|
||
|
|
return res.status(404).json({
|
||
|
|
success: false,
|
||
|
|
message: '解押申请不存在'
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
if (release.status !== 'pending') {
|
||
|
|
return res.status(400).json({
|
||
|
|
success: false,
|
||
|
|
message: '该申请已完成处理,无法重复操作'
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
const previousStatus = release.status;
|
||
|
|
let newStatus = release.status;
|
||
|
|
|
||
|
|
// 根据处理动作更新状态
|
||
|
|
if (action === 'approve') {
|
||
|
|
newStatus = 'approved';
|
||
|
|
} else if (action === 'reject') {
|
||
|
|
newStatus = 'rejected';
|
||
|
|
}
|
||
|
|
|
||
|
|
// 更新申请状态
|
||
|
|
release.status = newStatus;
|
||
|
|
release.process_date = new Date();
|
||
|
|
release.processor_id = req.user.userId;
|
||
|
|
release.processor_name = req.user.username;
|
||
|
|
release.process_comment = comment;
|
||
|
|
release.remark = remark;
|
||
|
|
|
||
|
|
if (action === 'reject') {
|
||
|
|
release.rejection_reason = comment;
|
||
|
|
}
|
||
|
|
|
||
|
|
await release.save();
|
||
|
|
|
||
|
|
// 创建历史记录
|
||
|
|
await LoanReleaseHistory.create({
|
||
|
|
release_id: release.id,
|
||
|
|
action: action,
|
||
|
|
operator: req.user.username,
|
||
|
|
operator_id: req.user.userId,
|
||
|
|
comment: comment,
|
||
|
|
previous_status: previousStatus,
|
||
|
|
new_status: newStatus
|
||
|
|
});
|
||
|
|
|
||
|
|
res.json({
|
||
|
|
success: true,
|
||
|
|
message: `解押申请已${action === 'approve' ? '通过' : '拒绝'}`,
|
||
|
|
data: {
|
||
|
|
id: release.id,
|
||
|
|
status: newStatus,
|
||
|
|
action,
|
||
|
|
comment
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
} catch (error) {
|
||
|
|
console.error('处理解押申请失败:', error);
|
||
|
|
res.status(500).json({
|
||
|
|
success: false,
|
||
|
|
message: '处理解押申请失败'
|
||
|
|
});
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 完成解押
|
||
|
|
* @param {Object} req - 请求对象
|
||
|
|
* @param {Object} res - 响应对象
|
||
|
|
*/
|
||
|
|
const completeRelease = async (req, res) => {
|
||
|
|
try {
|
||
|
|
const { id } = req.params;
|
||
|
|
const { comment } = req.body;
|
||
|
|
|
||
|
|
if (!req.user || !req.user.userId) {
|
||
|
|
return res.status(401).json({
|
||
|
|
success: false,
|
||
|
|
message: '用户信息无效'
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
const release = await LoanRelease.findByPk(id);
|
||
|
|
if (!release) {
|
||
|
|
return res.status(404).json({
|
||
|
|
success: false,
|
||
|
|
message: '解押申请不存在'
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
if (release.status !== 'approved') {
|
||
|
|
return res.status(400).json({
|
||
|
|
success: false,
|
||
|
|
message: '只有已通过的解押申请才能完成解押'
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
const previousStatus = release.status;
|
||
|
|
|
||
|
|
// 更新状态为已完成
|
||
|
|
release.status = 'completed';
|
||
|
|
release.complete_date = new Date();
|
||
|
|
await release.save();
|
||
|
|
|
||
|
|
// 创建历史记录
|
||
|
|
await LoanReleaseHistory.create({
|
||
|
|
release_id: release.id,
|
||
|
|
action: 'complete',
|
||
|
|
operator: req.user.username,
|
||
|
|
operator_id: req.user.userId,
|
||
|
|
comment: comment || '解押手续办理完成',
|
||
|
|
previous_status: previousStatus,
|
||
|
|
new_status: 'completed'
|
||
|
|
});
|
||
|
|
|
||
|
|
res.json({
|
||
|
|
success: true,
|
||
|
|
message: '解押完成',
|
||
|
|
data: {
|
||
|
|
id: release.id,
|
||
|
|
status: 'completed'
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
} catch (error) {
|
||
|
|
console.error('完成解押失败:', error);
|
||
|
|
res.status(500).json({
|
||
|
|
success: false,
|
||
|
|
message: '完成解押失败'
|
||
|
|
});
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 删除解押申请
|
||
|
|
* @param {Object} req - 请求对象
|
||
|
|
* @param {Object} res - 响应对象
|
||
|
|
*/
|
||
|
|
const deleteRelease = async (req, res) => {
|
||
|
|
try {
|
||
|
|
const { id } = req.params;
|
||
|
|
|
||
|
|
const release = await LoanRelease.findByPk(id);
|
||
|
|
if (!release) {
|
||
|
|
return res.status(404).json({
|
||
|
|
success: false,
|
||
|
|
message: '解押申请不存在'
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// 只有待处理状态的申请才能删除
|
||
|
|
if (release.status !== 'pending') {
|
||
|
|
return res.status(400).json({
|
||
|
|
success: false,
|
||
|
|
message: '只有待处理状态的申请才能删除'
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
await release.destroy();
|
||
|
|
|
||
|
|
res.json({
|
||
|
|
success: true,
|
||
|
|
message: '解押申请删除成功'
|
||
|
|
});
|
||
|
|
|
||
|
|
} catch (error) {
|
||
|
|
console.error('删除解押申请失败:', error);
|
||
|
|
res.status(500).json({
|
||
|
|
success: false,
|
||
|
|
message: '删除解押申请失败'
|
||
|
|
});
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 获取解押统计信息
|
||
|
|
* @param {Object} req - 请求对象
|
||
|
|
* @param {Object} res - 响应对象
|
||
|
|
*/
|
||
|
|
const getReleaseStats = async (req, res) => {
|
||
|
|
try {
|
||
|
|
const stats = await LoanRelease.findAll({
|
||
|
|
attributes: [
|
||
|
|
'status',
|
||
|
|
[require('sequelize').fn('COUNT', '*'), 'count']
|
||
|
|
],
|
||
|
|
group: ['status']
|
||
|
|
});
|
||
|
|
|
||
|
|
const totalCount = await LoanRelease.count();
|
||
|
|
const pendingCount = await LoanRelease.count({ where: { status: 'pending' } });
|
||
|
|
const processingCount = await LoanRelease.count({ where: { status: 'processing' } });
|
||
|
|
const completedCount = await LoanRelease.count({ where: { status: 'completed' } });
|
||
|
|
|
||
|
|
res.json({
|
||
|
|
success: true,
|
||
|
|
data: {
|
||
|
|
total: totalCount,
|
||
|
|
pending: pendingCount,
|
||
|
|
processing: processingCount,
|
||
|
|
completed: completedCount,
|
||
|
|
statusStats: stats
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
} catch (error) {
|
||
|
|
console.error('获取解押统计信息失败:', error);
|
||
|
|
res.status(500).json({
|
||
|
|
success: false,
|
||
|
|
message: '获取解押统计信息失败'
|
||
|
|
});
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
module.exports = {
|
||
|
|
getReleases,
|
||
|
|
getReleaseDetail,
|
||
|
|
createRelease,
|
||
|
|
updateRelease,
|
||
|
|
processRelease,
|
||
|
|
completeRelease,
|
||
|
|
deleteRelease,
|
||
|
|
getReleaseStats
|
||
|
|
};
|