添加银行政府后端接口

This commit is contained in:
2025-09-25 15:53:44 +08:00
parent b17bdcc24c
commit 5b6b7e0a96
60 changed files with 5345 additions and 1920 deletions

View File

@@ -1,77 +1,73 @@
/**
* 员工控制器
* @file employeeController.js
* @description 处理员工相关的请求
*/
const { Employee, Department, Position } = require('../models');
const { Employee, User } = require('../models');
const { validationResult } = require('express-validator');
const { Op } = require('sequelize');
const bcrypt = require('bcryptjs');
/**
* 获取员工列表
* @param {Object} req 请求对象
* @param {Object} res 响应对象
*/
exports.getEmployees = async (req, res) => {
const getEmployees = async (req, res) => {
try {
const {
page = 1,
limit = 10,
search = '',
department = '',
position = '',
pageSize = 10,
searchField = 'name',
searchValue = '',
status = '',
sortBy = 'created_at',
sortOrder = 'DESC'
isLoanSpecialist = ''
} = req.query;
const offset = (page - 1) * limit;
const whereClause = {};
// 搜索条件
if (search) {
whereClause[Op.or] = [
{ name: { [Op.like]: `%${search}%` } },
{ employee_id: { [Op.like]: `%${search}%` } },
{ phone: { [Op.like]: `%${search}%` } },
{ email: { [Op.like]: `%${search}%` } }
];
// 构建查询条件
const where = {};
if (searchValue) {
if (searchField === 'name') {
where.name = { [require('sequelize').Op.like]: `%${searchValue}%` };
} else if (searchField === 'phone') {
where.phone = { [require('sequelize').Op.like]: `%${searchValue}%` };
} else if (searchField === 'employeeNumber') {
where.employeeNumber = { [require('sequelize').Op.like]: `%${searchValue}%` };
}
}
// 部门筛选
if (department) {
whereClause.department_id = department;
}
// 职位筛选
if (position) {
whereClause.position_id = position;
}
// 状态筛选
if (status) {
whereClause.status = status;
where.status = status;
}
const { count, rows: employees } = await Employee.findAndCountAll({
where: whereClause,
include: [
{
model: Department,
as: 'department',
attributes: ['id', 'name']
},
{
model: Position,
as: 'position',
attributes: ['id', 'name', 'level']
}
],
order: [[sortBy, sortOrder.toUpperCase()]],
limit: parseInt(limit),
offset: parseInt(offset)
if (isLoanSpecialist !== '') {
where.isLoanSpecialist = isLoanSpecialist === 'true';
}
// 分页参数
const offset = (parseInt(page) - 1) * parseInt(pageSize);
const limit = parseInt(pageSize);
// 查询数据
const { count, rows } = await Employee.findAndCountAll({
where,
limit,
offset,
order: [['createdAt', 'DESC']],
attributes: {
exclude: ['password'] // 不返回密码
}
});
// 格式化数据
const employees = rows.map(employee => ({
id: employee.id,
employeeNumber: employee.employeeNumber,
name: employee.name,
phone: employee.phone,
email: employee.email,
isLoanSpecialist: employee.isLoanSpecialist,
department: employee.department,
position: employee.position,
status: employee.status,
lastLogin: employee.lastLogin,
createdAt: employee.createdAt,
updatedAt: employee.updatedAt
}));
res.json({
success: true,
message: '获取员工列表成功',
@@ -79,113 +75,32 @@ exports.getEmployees = async (req, res) => {
employees,
pagination: {
current: parseInt(page),
pageSize: parseInt(limit),
pageSize: parseInt(pageSize),
total: count,
pages: Math.ceil(count / limit)
pages: Math.ceil(count / parseInt(pageSize))
}
}
});
} catch (error) {
console.error('获取员工列表错误:', error);
console.error('获取员工列表失败:', error);
res.status(500).json({
success: false,
message: '服务器内部错误',
error: error.message
});
}
};
/**
* 创建员工
* @param {Object} req 请求对象
* @param {Object} res 响应对象
*/
exports.createEmployee = async (req, res) => {
try {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
success: false,
message: '输入数据验证失败',
errors: errors.array()
});
}
const {
name,
employee_id,
department_id,
position_id,
phone,
email,
hire_date,
salary,
status = 'active'
} = req.body;
// 检查员工编号是否已存在
const existingEmployee = await Employee.findOne({
where: { employee_id }
});
if (existingEmployee) {
return res.status(400).json({
success: false,
message: '员工编号已存在'
});
}
const employee = await Employee.create({
name,
employee_id,
department_id,
position_id,
phone,
email,
hire_date,
salary: salary * 100, // 转换为分
status
});
res.status(201).json({
success: true,
message: '创建员工成功',
data: employee
});
} catch (error) {
console.error('创建员工错误:', error);
res.status(500).json({
success: false,
message: '服务器内部错误',
error: error.message
message: '获取员工列表失败'
});
}
};
/**
* 获取员工详情
* @param {Object} req 请求对象
* @param {Object} res 响应对象
*/
exports.getEmployeeById = async (req, res) => {
const getEmployeeById = async (req, res) => {
try {
const { id } = req.params;
const employee = await Employee.findByPk(id, {
include: [
{
model: Department,
as: 'department',
attributes: ['id', 'name', 'description']
},
{
model: Position,
as: 'position',
attributes: ['id', 'name', 'level', 'description']
}
]
attributes: {
exclude: ['password'] // 不返回密码
}
});
if (!employee) {
@@ -200,43 +115,128 @@ exports.getEmployeeById = async (req, res) => {
message: '获取员工详情成功',
data: employee
});
} catch (error) {
console.error('获取员工详情错误:', error);
console.error('获取员工详情失败:', error);
res.status(500).json({
success: false,
message: '服务器内部错误',
error: error.message
message: '获取员工详情失败'
});
}
};
/**
* 更新员工
* @param {Object} req 请求对象
* @param {Object} res 响应对象
* 创建员工
*/
exports.updateEmployee = async (req, res) => {
const createEmployee = async (req, res) => {
try {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
success: false,
message: '输入数据验证失败',
message: '请求参数错误',
errors: errors.array()
});
}
const {
employeeNumber,
name,
phone,
email,
password,
isLoanSpecialist,
department,
position
} = req.body;
// 检查员工编号是否已存在
const existingEmployee = await Employee.findOne({
where: { employeeNumber }
});
if (existingEmployee) {
return res.status(400).json({
success: false,
message: '员工编号已存在'
});
}
// 检查手机号是否已存在
const existingPhone = await Employee.findOne({
where: { phone }
});
if (existingPhone) {
return res.status(400).json({
success: false,
message: '手机号已存在'
});
}
// 创建员工
const employee = await Employee.create({
employeeNumber,
name,
phone,
email,
password: password || '123456', // 默认密码
isLoanSpecialist: isLoanSpecialist || false,
department,
position,
status: 'active'
});
res.status(201).json({
success: true,
message: '创建员工成功',
data: {
id: employee.id,
employeeNumber: employee.employeeNumber,
name: employee.name,
phone: employee.phone,
email: employee.email,
isLoanSpecialist: employee.isLoanSpecialist,
department: employee.department,
position: employee.position,
status: employee.status,
createdAt: employee.createdAt
}
});
} catch (error) {
console.error('创建员工失败:', error);
res.status(500).json({
success: false,
message: '创建员工失败'
});
}
};
/**
* 更新员工信息
*/
const updateEmployee = 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;
// 如果更新薪资,转换为分
if (updateData.salary) {
updateData.salary = updateData.salary * 100;
}
const {
name,
phone,
email,
isLoanSpecialist,
department,
position,
status
} = req.body;
const employee = await Employee.findByPk(id);
if (!employee) {
return res.status(404).json({
success: false,
@@ -244,35 +244,101 @@ exports.updateEmployee = async (req, res) => {
});
}
await employee.update(updateData);
// 检查手机号是否被其他员工使用
if (phone && phone !== employee.phone) {
const existingPhone = await Employee.findOne({
where: {
phone,
id: { [require('sequelize').Op.ne]: id }
}
});
if (existingPhone) {
return res.status(400).json({
success: false,
message: '手机号已被其他员工使用'
});
}
}
// 更新员工信息
await employee.update({
name,
phone,
email,
isLoanSpecialist,
department,
position,
status
});
res.json({
success: true,
message: '更新员工成功',
data: employee
message: '更新员工信息成功',
data: {
id: employee.id,
employeeNumber: employee.employeeNumber,
name: employee.name,
phone: employee.phone,
email: employee.email,
isLoanSpecialist: employee.isLoanSpecialist,
department: employee.department,
position: employee.position,
status: employee.status,
updatedAt: employee.updatedAt
}
});
} catch (error) {
console.error('更新员工错误:', error);
console.error('更新员工信息失败:', error);
res.status(500).json({
success: false,
message: '服务器内部错误',
error: error.message
message: '更新员工信息失败'
});
}
};
/**
* 重设密码
*/
const resetPassword = async (req, res) => {
try {
const { id } = req.params;
const { newPassword } = req.body;
const employee = await Employee.findByPk(id);
if (!employee) {
return res.status(404).json({
success: false,
message: '员工不存在'
});
}
// 更新密码
await employee.update({
password: newPassword || '123456' // 默认密码
});
res.json({
success: true,
message: '重设密码成功'
});
} catch (error) {
console.error('重设密码失败:', error);
res.status(500).json({
success: false,
message: '重设密码失败'
});
}
};
/**
* 删除员工
* @param {Object} req 请求对象
* @param {Object} res 响应对象
*/
exports.deleteEmployee = async (req, res) => {
const deleteEmployee = async (req, res) => {
try {
const { id } = req.params;
const employee = await Employee.findByPk(id);
if (!employee) {
return res.status(404).json({
success: false,
@@ -280,87 +346,105 @@ exports.deleteEmployee = async (req, res) => {
});
}
// 软删除
await employee.destroy();
res.json({
success: true,
message: '删除员工成功'
});
} catch (error) {
console.error('删除员工错误:', error);
console.error('删除员工失败:', error);
res.status(500).json({
success: false,
message: '服务器内部错误',
error: error.message
message: '删除员工失败'
});
}
};
/**
* 获取员工统计
* @param {Object} req 请求对象
* @param {Object} res 响应对象
* 批量更新员工状态
*/
exports.getEmployeeStats = async (req, res) => {
const batchUpdateStatus = async (req, res) => {
try {
const { ids, status } = req.body;
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: '请选择要更新的状态'
});
}
await Employee.update(
{
status
},
{
where: {
id: { [require('sequelize').Op.in]: ids }
}
}
);
res.json({
success: true,
message: '批量更新状态成功'
});
} catch (error) {
console.error('批量更新状态失败:', error);
res.status(500).json({
success: false,
message: '批量更新状态失败'
});
}
};
/**
* 获取员工统计信息
*/
const getEmployeeStats = async (req, res) => {
try {
const totalEmployees = await Employee.count();
const activeEmployees = await Employee.count({ where: { status: 'active' } });
const inactiveEmployees = await Employee.count({ where: { status: 'inactive' } });
const departmentStats = await Employee.findAll({
attributes: [
'department_id',
[Employee.sequelize.fn('COUNT', Employee.sequelize.col('id')), 'count']
],
include: [{
model: Department,
as: 'department',
attributes: ['name']
}],
group: ['department_id', 'department.id'],
raw: false
});
const positionStats = await Employee.findAll({
attributes: [
'position_id',
[Employee.sequelize.fn('COUNT', Employee.sequelize.col('id')), 'count']
],
include: [{
model: Position,
as: 'position',
attributes: ['name', 'level']
}],
group: ['position_id', 'position.id'],
raw: false
});
const lockedEmployees = await Employee.count({ where: { status: 'locked' } });
const loanSpecialists = await Employee.count({ where: { isLoanSpecialist: true } });
res.json({
success: true,
message: '获取员工统计成功',
data: {
total: totalEmployees,
active: activeEmployees,
inactive: inactiveEmployees,
departmentStats: departmentStats.map(item => ({
department: item.department.name,
count: parseInt(item.dataValues.count)
})),
positionStats: positionStats.map(item => ({
position: item.position.name,
level: item.position.level,
count: parseInt(item.dataValues.count)
}))
totalEmployees,
activeEmployees,
inactiveEmployees,
lockedEmployees,
loanSpecialists
}
});
} catch (error) {
console.error('获取员工统计错误:', error);
console.error('获取员工统计失败:', error);
res.status(500).json({
success: false,
message: '服务器内部错误',
error: error.message
message: '获取员工统计失败'
});
}
};
module.exports = {
getEmployees,
getEmployeeById,
createEmployee,
updateEmployee,
resetPassword,
deleteEmployee,
batchUpdateStatus,
getEmployeeStats
};

View File

@@ -29,15 +29,12 @@ const getApplications = async (req, res) => {
// 搜索条件
if (searchValue) {
if (searchField === 'applicationNumber') {
where.applicationNumber = { [Op.like]: `%${searchValue}%` };
} else if (searchField === 'customerName') {
where[Op.or] = [
{ borrowerName: { [Op.like]: `%${searchValue}%` } },
{ farmerName: { [Op.like]: `%${searchValue}%` } }
];
} else if (searchField === 'productName') {
where.productName = { [Op.like]: `%${searchValue}%` };
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}%` };
}
}
@@ -56,35 +53,6 @@ const getApplications = async (req, res) => {
// 查询数据
const { count, rows } = await LoanApplication.findAndCountAll({
where,
include: [
{
model: User,
as: 'applicant',
attributes: ['id', 'username', 'real_name']
},
{
model: User,
as: 'approver',
attributes: ['id', 'username', 'real_name']
},
{
model: User,
as: 'rejector',
attributes: ['id', 'username', 'real_name']
},
{
model: AuditRecord,
as: 'auditRecords',
include: [
{
model: User,
as: 'auditorUser',
attributes: ['id', 'username', 'real_name']
}
],
order: [['auditTime', 'DESC']]
}
],
order,
offset,
limit
@@ -93,34 +61,16 @@ const getApplications = async (req, res) => {
// 格式化数据
const applications = rows.map(app => ({
id: app.id,
applicationNumber: app.applicationNumber,
productName: app.productName,
farmerName: app.farmerName,
borrowerName: app.borrowerName,
borrowerIdNumber: app.borrowerIdNumber,
assetType: app.assetType,
applicationQuantity: app.applicationQuantity,
amount: parseFloat(app.amount),
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,
status: app.status,
type: app.type,
term: app.term,
interestRate: parseFloat(app.interestRate),
phone: app.phone,
purpose: app.purpose,
remark: app.remark,
applicationTime: app.applicationTime,
approvedTime: app.approvedTime,
rejectedTime: app.rejectedTime,
auditRecords: app.auditRecords.map(record => ({
id: record.id,
action: record.action,
auditor: record.auditorUser?.real_name || record.auditor,
auditorId: record.auditorId,
comment: record.comment,
time: record.auditTime,
previousStatus: record.previousStatus,
newStatus: record.newStatus
}))
created_at: app.created_at,
updated_at: app.updated_at
}));
res.json({

View File

@@ -30,15 +30,13 @@ const getContracts = async (req, res) => {
// 搜索条件
if (searchValue) {
if (searchField === 'contractNumber') {
where.contractNumber = { [Op.like]: `%${searchValue}%` };
} else if (searchField === 'applicationNumber') {
where.applicationNumber = { [Op.like]: `%${searchValue}%` };
} else if (searchField === 'borrowerName') {
where.borrowerName = { [Op.like]: `%${searchValue}%` };
} else if (searchField === 'farmerName') {
where.farmerName = { [Op.like]: `%${searchValue}%` };
} else if (searchField === 'productName') {
where.productName = { [Op.like]: `%${searchValue}%` };
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}%` };
}
}
@@ -57,18 +55,6 @@ const getContracts = async (req, res) => {
// 查询数据
const { count, rows } = await LoanContract.findAndCountAll({
where,
include: [
{
model: User,
as: 'creator',
attributes: ['id', 'username', 'real_name']
},
{
model: User,
as: 'updater',
attributes: ['id', 'username', 'real_name']
}
],
order,
offset,
limit
@@ -77,31 +63,17 @@ const getContracts = async (req, res) => {
// 格式化数据
const contracts = rows.map(contract => ({
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),
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,
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
created_at: contract.created_at,
updated_at: contract.updated_at
}));
res.json({

View File

@@ -1,5 +1,6 @@
const { LoanProduct, User } = require('../models');
const { Op } = require('sequelize');
const { sequelize } = require('../config/database');
// 获取贷款商品列表
const getLoanProducts = async (req, res) => {
@@ -17,23 +18,37 @@ const getLoanProducts = async (req, res) => {
const offset = (page - 1) * limit;
const whereClause = {};
// 字段映射 - 将模型属性名映射到数据库字段名
const fieldMapping = {
'createdAt': 'created_at',
'updatedAt': 'updated_at',
'productName': 'product_name',
'loanAmount': 'loan_amount',
'loanTerm': 'loan_term',
'interestRate': 'interest_rate',
'serviceArea': 'service_area',
'servicePhone': 'service_phone',
'onSaleStatus': 'on_sale_status',
'riskLevel': 'risk_level'
};
// 搜索条件
if (search) {
whereClause[Op.or] = [
{ productName: { [Op.like]: `%${search}%` } },
{ serviceArea: { [Op.like]: `%${search}%` } },
{ servicePhone: { [Op.like]: `%${search}%` } }
{ product_name: { [Op.like]: `%${search}%` } },
{ service_area: { [Op.like]: `%${search}%` } },
{ service_phone: { [Op.like]: `%${search}%` } }
];
}
// 在售状态筛选
if (onSaleStatus !== undefined) {
whereClause.onSaleStatus = onSaleStatus === 'true';
whereClause.on_sale_status = onSaleStatus === 'true';
}
// 风险等级筛选
if (riskLevel) {
whereClause.riskLevel = riskLevel;
whereClause.risk_level = riskLevel;
}
const { count, rows } = await LoanProduct.findAndCountAll({
@@ -50,7 +65,7 @@ const getLoanProducts = async (req, res) => {
attributes: ['id', 'username', 'real_name']
}
],
order: [[sortBy, sortOrder.toUpperCase()]],
order: [[fieldMapping[sortBy] || sortBy, sortOrder.toUpperCase()]],
limit: parseInt(limit),
offset: parseInt(offset)
});