修改政府端前端,银行端小程序和后端接口

This commit is contained in:
2025-09-26 17:52:50 +08:00
parent 852adbcfff
commit 00dfa83fd1
237 changed files with 9172 additions and 33500 deletions

View File

@@ -38,6 +38,9 @@ const getApplications = async (req, res) => {
} else if (searchField === 'applicationNumber') {
// 数据库中实际没有applicationNumber字段使用id作为替代
where.id = { [Op.like]: `%${searchValue}%` };
} else if (searchField === 'productName') {
// 产品名称搜索暂时不处理,因为数据库中没有这个字段
// 可以在前端过滤
}
}
@@ -70,17 +73,27 @@ const getApplications = async (req, res) => {
limit
});
// 格式化数据
// 格式化数据 - 匹配前端期望的字段
const applications = rows.map(app => ({
id: app.id,
customer_name: app.customer_name,
customer_phone: app.customer_phone,
customer_id_card: app.customer_id_card,
loan_amount: parseFloat(app.loan_amount),
loan_term: app.loan_term,
interest_rate: parseFloat(app.interest_rate),
application_date: app.application_date,
applicationNumber: `APP-${String(app.id).padStart(6, '0')}`, // 生成申请单号
productName: '养殖贷款', // 默认产品名称
farmerName: app.customer_name || '未知养殖户',
borrowerName: app.customer_name || '未知借款人',
borrowerIdNumber: app.customer_id_card || '',
assetType: '养殖设备', // 默认生资种类
applicationQuantity: '1', // 默认申请数量
amount: parseFloat(app.loan_amount),
status: app.status,
type: 'personal', // 默认类型
term: app.loan_term,
interestRate: parseFloat(app.interest_rate),
phone: app.customer_phone || '',
purpose: '养殖经营', // 默认用途
remark: '', // 默认备注
applicationTime: app.application_date,
approvedTime: null,
rejectedTime: null,
created_at: app.created_at,
updated_at: app.updated_at
}));
@@ -221,7 +234,7 @@ const auditApplication = async (req, res) => {
const { id } = req.params;
const { action, comment } = req.body;
const userId = req.user?.id;
const userId = req.user?.userId;
// 获取申请信息
const application = await LoanApplication.findByPk(id);
@@ -246,13 +259,15 @@ const auditApplication = async (req, res) => {
// 根据审核动作更新状态
if (action === 'approve') {
newStatus = 'approved';
application.approvedTime = new Date();
application.approvedBy = userId;
// 注意LoanApplication模型中没有这些字段暂时注释掉
// application.approvedTime = new Date();
// application.approvedBy = userId;
} else if (action === 'reject') {
newStatus = 'rejected';
application.rejectedTime = new Date();
application.rejectedBy = userId;
application.rejectionReason = comment;
// 注意LoanApplication模型中没有这些字段暂时注释掉
// application.rejectedTime = new Date();
// application.rejectedBy = userId;
// application.rejectionReason = comment;
}
// 更新申请状态
@@ -283,9 +298,12 @@ const auditApplication = async (req, res) => {
});
} catch (error) {
console.error('审核贷款申请失败:', error);
console.error('错误详情:', error.message);
console.error('错误堆栈:', error.stack);
res.status(500).json({
success: false,
message: '审核贷款申请失败'
message: '审核贷款申请失败',
error: error.message
});
}
};

View File

@@ -40,6 +40,13 @@ const getContracts = async (req, res) => {
} 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') {
// 产品名称搜索暂时不处理,因为数据库中没有这个字段
// 可以在前端过滤
}
}
@@ -72,18 +79,32 @@ const getContracts = async (req, res) => {
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,
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
}));

View File

@@ -201,7 +201,7 @@ const createLoanProduct = async (req, res) => {
}
// 检查用户信息
if (!req.user || !req.user.id) {
if (!req.user || !req.user.userId) {
return res.status(401).json({
success: false,
message: '用户信息无效'
@@ -222,8 +222,8 @@ const createLoanProduct = async (req, res) => {
riskLevel,
minLoanAmount: minLoanAmount ? parseFloat(minLoanAmount) : null,
maxLoanAmount: maxLoanAmount ? parseFloat(maxLoanAmount) : null,
createdBy: req.user.id,
updatedBy: req.user.id
createdBy: req.user.userId,
updatedBy: req.user.userId
});
// 获取创建后的完整信息
@@ -313,7 +313,7 @@ const updateLoanProduct = async (req, res) => {
}
});
product.updatedBy = req.user.id;
product.updatedBy = req.user.userId;
await product.save();
// 获取更新后的完整信息
@@ -440,7 +440,7 @@ const batchUpdateStatus = async (req, res) => {
await LoanProduct.update(
{
onSaleStatus,
updatedBy: req.user.id
updatedBy: req.user.userId
},
{
where: { id: { [Op.in]: ids } }

View File

@@ -0,0 +1,545 @@
/**
* 贷款解押控制器
* @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
};