添加银行后端接口,前端代码
This commit is contained in:
164
bank-backend/SUPERVISION_TASKS_INTEGRATION_SUMMARY.md
Normal file
164
bank-backend/SUPERVISION_TASKS_INTEGRATION_SUMMARY.md
Normal file
@@ -0,0 +1,164 @@
|
||||
# 监管任务前后端集成完成总结
|
||||
|
||||
## 🎯 项目概述
|
||||
已成功完成银行端监管任务管理系统的前后端集成,实现了完整的CRUD功能,使用真实的后端API接口替代了前端模拟数据。
|
||||
|
||||
## ✅ 已完成的功能
|
||||
|
||||
### 后端功能
|
||||
1. **数据库模型** (`models/SupervisionTask.js`)
|
||||
- 完整的监管任务数据模型
|
||||
- 支持所有必要字段:申请单号、合同编号、客户信息、监管信息等
|
||||
- 与用户模型的关联关系
|
||||
|
||||
2. **数据库迁移** (`migrations/20241220000003-create-supervision-tasks.js`)
|
||||
- 创建监管任务表结构
|
||||
- 添加必要的索引优化查询性能
|
||||
|
||||
3. **API控制器** (`controllers/supervisionTaskController.js`)
|
||||
- 获取监管任务列表(支持分页、搜索、筛选)
|
||||
- 获取监管任务详情
|
||||
- 创建监管任务(完整的数据验证)
|
||||
- 更新监管任务
|
||||
- 删除监管任务
|
||||
- 获取监管任务统计
|
||||
- 批量更新状态
|
||||
- 批量删除
|
||||
|
||||
4. **API路由** (`routes/supervisionTasks.js`)
|
||||
- 完整的RESTful API路由配置
|
||||
- 统一的认证中间件保护
|
||||
|
||||
5. **测试数据** (`scripts/seed-supervision-tasks.js`)
|
||||
- 8条完整的测试数据
|
||||
- 涵盖不同状态和类型的监管任务
|
||||
|
||||
### 前端功能
|
||||
1. **API集成** (`src/utils/api.js`)
|
||||
- 完整的监管任务API方法
|
||||
- 统一的错误处理和认证
|
||||
|
||||
2. **页面改造** (`src/views/SupervisionTasks.vue`)
|
||||
- 移除模拟数据,使用真实API
|
||||
- 实现完整的CRUD操作
|
||||
- 添加搜索和筛选功能
|
||||
- 分页功能
|
||||
- 错误处理和用户反馈
|
||||
|
||||
## 📊 数据字段说明
|
||||
|
||||
### 核心字段
|
||||
- **申请单号** (`applicationNumber`): 唯一标识,最大50字符
|
||||
- **放款合同编号** (`contractNumber`): 唯一标识,最大50字符
|
||||
- **产品名称** (`productName`): 最大100字符
|
||||
- **客户姓名** (`customerName`): 最大50字符
|
||||
- **证件类型** (`idType`): 枚举值(身份证、护照、其他)
|
||||
- **证件号码** (`idNumber`): 最大50字符
|
||||
- **养殖生资种类** (`assetType`): 枚举值(牛、羊、猪、家禽、其他)
|
||||
- **监管生资数量** (`assetQuantity`): 非负整数
|
||||
- **监管状态** (`supervisionStatus`): 枚举值(待监管、监管中、已完成、已暂停)
|
||||
|
||||
### 时间字段
|
||||
- **任务导入时间** (`importTime`): 自动生成
|
||||
- **监管起始时间** (`startTime`): 必填
|
||||
- **监管结束时间** (`endTime`): 必填
|
||||
|
||||
### 扩展字段
|
||||
- **贷款金额** (`loanAmount`): 精确到分
|
||||
- **利率** (`interestRate`): 精确到万分位
|
||||
- **贷款期限** (`loanTerm`): 月数
|
||||
- **监管员姓名** (`supervisorName`): 最大50字符
|
||||
- **监管员电话** (`supervisorPhone`): 最大20字符
|
||||
- **养殖场地址** (`farmAddress`): 最大200字符
|
||||
- **备注** (`remarks`): 文本字段
|
||||
|
||||
## 🔧 API接口列表
|
||||
|
||||
### 基础CRUD
|
||||
- `GET /api/supervision-tasks` - 获取监管任务列表
|
||||
- `GET /api/supervision-tasks/:id` - 获取监管任务详情
|
||||
- `POST /api/supervision-tasks` - 创建监管任务
|
||||
- `PUT /api/supervision-tasks/:id` - 更新监管任务
|
||||
- `DELETE /api/supervision-tasks/:id` - 删除监管任务
|
||||
|
||||
### 统计和批量操作
|
||||
- `GET /api/supervision-tasks/stats` - 获取监管任务统计
|
||||
- `PUT /api/supervision-tasks/batch/status` - 批量更新状态
|
||||
- `DELETE /api/supervision-tasks/batch` - 批量删除
|
||||
|
||||
### 查询参数
|
||||
- `page`: 页码(默认1)
|
||||
- `limit`: 每页数量(默认10)
|
||||
- `search`: 搜索关键词(申请单号、合同编号、客户姓名、产品名称)
|
||||
- `supervisionStatus`: 状态筛选
|
||||
- `dateRange`: 日期范围筛选
|
||||
- `sortBy`: 排序字段
|
||||
- `sortOrder`: 排序方向
|
||||
|
||||
## 🚀 使用方法
|
||||
|
||||
### 1. 启动后端服务
|
||||
```bash
|
||||
cd bank-backend
|
||||
npm start
|
||||
```
|
||||
|
||||
### 2. 启动前端服务
|
||||
```bash
|
||||
cd bank-frontend
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### 3. 访问页面
|
||||
- 监管任务页面: `http://localhost:5300/supervision-tasks`
|
||||
- API测试页面: `http://localhost:5300/test-supervision-tasks.html`
|
||||
|
||||
### 4. 功能测试
|
||||
1. 登录系统(admin/Admin123456)
|
||||
2. 查看监管任务列表
|
||||
3. 使用搜索和筛选功能
|
||||
4. 创建新的监管任务
|
||||
5. 编辑和删除任务
|
||||
|
||||
## 📝 数据验证规则
|
||||
|
||||
### 必填字段
|
||||
- 申请单号、放款合同编号、产品名称、客户姓名、证件号码、监管起始时间、监管结束时间
|
||||
|
||||
### 唯一性约束
|
||||
- 申请单号、放款合同编号必须唯一
|
||||
|
||||
### 数据格式
|
||||
- 日期格式:YYYY-MM-DD
|
||||
- 金额格式:精确到分
|
||||
- 利率格式:0-1之间的小数
|
||||
|
||||
### 业务规则
|
||||
- 监管结束时间必须晚于开始时间
|
||||
- 监管生资数量不能为负数
|
||||
- 贷款金额不能为负数
|
||||
|
||||
## 🔍 测试数据
|
||||
|
||||
系统已预置8条测试数据,涵盖:
|
||||
- 不同监管状态(待监管、监管中、已完成、已暂停)
|
||||
- 不同养殖生资种类(牛、羊、猪、家禽、其他)
|
||||
- 不同证件类型(身份证、护照)
|
||||
- 不同贷款金额和期限
|
||||
|
||||
## 📚 相关文档
|
||||
|
||||
- [监管任务API文档](docs/SUPERVISION_TASKS_API.md)
|
||||
- [项目API文档](docs/PROJECT_API.md)
|
||||
- [前端API集成指南](API_INTEGRATION_COMPLETE.md)
|
||||
|
||||
## 🎉 总结
|
||||
|
||||
监管任务管理系统已完全集成,提供了:
|
||||
- ✅ 完整的后端API服务
|
||||
- ✅ 功能丰富的前端界面
|
||||
- ✅ 真实的数据存储和查询
|
||||
- ✅ 完善的错误处理
|
||||
- ✅ 用户友好的交互体验
|
||||
|
||||
系统现在可以正常使用,支持监管任务的完整生命周期管理。
|
||||
460
bank-backend/controllers/projectController.js
Normal file
460
bank-backend/controllers/projectController.js
Normal file
@@ -0,0 +1,460 @@
|
||||
const { Project, User } = require('../models');
|
||||
const { Op } = require('sequelize');
|
||||
|
||||
// 获取项目列表
|
||||
const getProjects = async (req, res) => {
|
||||
try {
|
||||
const {
|
||||
page = 1,
|
||||
limit = 10,
|
||||
search = '',
|
||||
status = '',
|
||||
sortBy = 'createdAt',
|
||||
sortOrder = 'DESC'
|
||||
} = req.query;
|
||||
|
||||
const offset = (page - 1) * limit;
|
||||
|
||||
// 构建查询条件
|
||||
const where = {};
|
||||
|
||||
// 搜索条件
|
||||
if (search) {
|
||||
where[Op.or] = [
|
||||
{ name: { [Op.like]: `%${search}%` } },
|
||||
{ farmName: { [Op.like]: `%${search}%` } },
|
||||
{ loanOfficer: { [Op.like]: `%${search}%` } }
|
||||
];
|
||||
}
|
||||
|
||||
// 状态筛选
|
||||
if (status) {
|
||||
where.status = status;
|
||||
}
|
||||
|
||||
// 查询项目列表
|
||||
const { count, rows: projects } = await Project.findAndCountAll({
|
||||
where,
|
||||
include: [
|
||||
{
|
||||
model: User,
|
||||
as: 'creator',
|
||||
attributes: ['id', 'username', 'real_name']
|
||||
},
|
||||
{
|
||||
model: User,
|
||||
as: 'updater',
|
||||
attributes: ['id', 'username', 'real_name']
|
||||
}
|
||||
],
|
||||
order: [[sortBy, sortOrder.toUpperCase()]],
|
||||
limit: parseInt(limit),
|
||||
offset: parseInt(offset)
|
||||
});
|
||||
|
||||
// 计算分页信息
|
||||
const totalPages = Math.ceil(count / limit);
|
||||
const hasNextPage = page < totalPages;
|
||||
const hasPrevPage = page > 1;
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
projects,
|
||||
pagination: {
|
||||
current: parseInt(page),
|
||||
pageSize: parseInt(limit),
|
||||
total: count,
|
||||
totalPages,
|
||||
hasNextPage,
|
||||
hasPrevPage
|
||||
}
|
||||
},
|
||||
message: '获取项目列表成功'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取项目列表失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '获取项目列表失败',
|
||||
error: process.env.NODE_ENV === 'development' ? error.message : undefined
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 获取项目详情
|
||||
const getProjectById = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
const project = await Project.findByPk(id, {
|
||||
include: [
|
||||
{
|
||||
model: User,
|
||||
as: 'creator',
|
||||
attributes: ['id', 'username', 'name']
|
||||
},
|
||||
{
|
||||
model: User,
|
||||
as: 'updater',
|
||||
attributes: ['id', 'username', 'name']
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
if (!project) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '项目不存在'
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: project,
|
||||
message: '获取项目详情成功'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取项目详情失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '获取项目详情失败',
|
||||
error: process.env.NODE_ENV === 'development' ? error.message : undefined
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 创建项目
|
||||
const createProject = async (req, res) => {
|
||||
try {
|
||||
const {
|
||||
name,
|
||||
status = 'supervision',
|
||||
farmName,
|
||||
supervisionObject,
|
||||
supervisionQuantity = 0,
|
||||
supervisionPeriod,
|
||||
supervisionAmount = 0.00,
|
||||
startTime,
|
||||
endTime,
|
||||
earTag = 0,
|
||||
collar = 0,
|
||||
host = 0,
|
||||
loanOfficer,
|
||||
description
|
||||
} = req.body;
|
||||
|
||||
// 验证必填字段
|
||||
const requiredFields = ['name', 'farmName', 'supervisionObject', 'supervisionPeriod', 'startTime', 'endTime'];
|
||||
const missingFields = requiredFields.filter(field => !req.body[field]);
|
||||
|
||||
if (missingFields.length > 0) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: `请填写所有必填字段: ${missingFields.join(', ')}`
|
||||
});
|
||||
}
|
||||
|
||||
// 验证字段长度
|
||||
if (name.length > 100) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '项目名称不能超过100个字符'
|
||||
});
|
||||
}
|
||||
|
||||
if (farmName.length > 200) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '养殖场名称不能超过200个字符'
|
||||
});
|
||||
}
|
||||
|
||||
// 验证数值字段
|
||||
if (supervisionQuantity < 0) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '监管数量不能为负数'
|
||||
});
|
||||
}
|
||||
|
||||
if (supervisionAmount < 0) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '监管金额不能为负数'
|
||||
});
|
||||
}
|
||||
|
||||
if (earTag < 0 || collar < 0 || host < 0) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '设备数量不能为负数'
|
||||
});
|
||||
}
|
||||
|
||||
// 验证状态
|
||||
if (!['supervision', 'completed'].includes(status)) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '项目状态只能是 supervision 或 completed'
|
||||
});
|
||||
}
|
||||
|
||||
// 验证日期格式和逻辑
|
||||
const startDate = new Date(startTime);
|
||||
const endDate = new Date(endTime);
|
||||
|
||||
if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '日期格式不正确'
|
||||
});
|
||||
}
|
||||
|
||||
if (startDate >= endDate) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '结束时间必须晚于开始时间'
|
||||
});
|
||||
}
|
||||
|
||||
// 检查项目名称是否已存在
|
||||
const existingProject = await Project.findOne({
|
||||
where: { name }
|
||||
});
|
||||
|
||||
if (existingProject) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '项目名称已存在,请使用其他名称'
|
||||
});
|
||||
}
|
||||
|
||||
// 创建项目
|
||||
const project = await Project.create({
|
||||
name,
|
||||
status,
|
||||
farmName,
|
||||
supervisionObject,
|
||||
supervisionQuantity: parseInt(supervisionQuantity),
|
||||
supervisionPeriod,
|
||||
supervisionAmount: parseFloat(supervisionAmount),
|
||||
startTime,
|
||||
endTime,
|
||||
earTag: parseInt(earTag),
|
||||
collar: parseInt(collar),
|
||||
host: parseInt(host),
|
||||
loanOfficer,
|
||||
description,
|
||||
createdBy: req.user?.userId || req.user?.id,
|
||||
updatedBy: req.user?.userId || req.user?.id
|
||||
});
|
||||
|
||||
// 获取创建的项目详情(包含关联信息)
|
||||
const createdProject = await Project.findByPk(project.id, {
|
||||
include: [
|
||||
{
|
||||
model: User,
|
||||
as: 'creator',
|
||||
attributes: ['id', 'username', 'real_name']
|
||||
},
|
||||
{
|
||||
model: User,
|
||||
as: 'updater',
|
||||
attributes: ['id', 'username', 'real_name']
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
res.status(201).json({
|
||||
success: true,
|
||||
data: createdProject,
|
||||
message: '创建项目成功'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('创建项目失败:', error);
|
||||
|
||||
// 处理数据库约束错误
|
||||
if (error.name === 'SequelizeValidationError') {
|
||||
const validationErrors = error.errors.map(err => err.message).join(', ');
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: `数据验证失败: ${validationErrors}`
|
||||
});
|
||||
}
|
||||
|
||||
if (error.name === 'SequelizeUniqueConstraintError') {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '项目名称已存在,请使用其他名称'
|
||||
});
|
||||
}
|
||||
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '创建项目失败',
|
||||
error: process.env.NODE_ENV === 'development' ? error.message : undefined
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 更新项目
|
||||
const updateProject = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const updateData = req.body;
|
||||
|
||||
// 验证日期
|
||||
if (updateData.startTime && updateData.endTime) {
|
||||
if (new Date(updateData.startTime) >= new Date(updateData.endTime)) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '结束时间必须晚于开始时间'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const project = await Project.findByPk(id);
|
||||
if (!project) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '项目不存在'
|
||||
});
|
||||
}
|
||||
|
||||
// 更新项目
|
||||
await project.update({
|
||||
...updateData,
|
||||
updatedBy: req.user?.id
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: project,
|
||||
message: '更新项目成功'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('更新项目失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '更新项目失败',
|
||||
error: process.env.NODE_ENV === 'development' ? error.message : undefined
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 删除项目
|
||||
const deleteProject = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
const project = await Project.findByPk(id);
|
||||
if (!project) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '项目不存在'
|
||||
});
|
||||
}
|
||||
|
||||
await project.destroy();
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '删除项目成功'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('删除项目失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '删除项目失败',
|
||||
error: process.env.NODE_ENV === 'development' ? error.message : undefined
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 获取项目统计
|
||||
const getProjectStats = async (req, res) => {
|
||||
try {
|
||||
const totalProjects = await Project.count();
|
||||
const supervisionProjects = await Project.count({ where: { status: 'supervision' } });
|
||||
const completedProjects = await Project.count({ where: { status: 'completed' } });
|
||||
|
||||
// 计算总监管金额
|
||||
const totalAmount = await Project.sum('supervisionAmount');
|
||||
|
||||
// 计算总监管数量
|
||||
const totalQuantity = await Project.sum('supervisionQuantity');
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
total: totalProjects,
|
||||
supervision: supervisionProjects,
|
||||
completed: completedProjects,
|
||||
totalAmount: totalAmount || 0,
|
||||
totalQuantity: totalQuantity || 0
|
||||
},
|
||||
message: '获取项目统计成功'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取项目统计失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '获取项目统计失败',
|
||||
error: process.env.NODE_ENV === 'development' ? error.message : undefined
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 批量更新项目状态
|
||||
const batchUpdateStatus = async (req, res) => {
|
||||
try {
|
||||
const { projectIds, status } = req.body;
|
||||
|
||||
if (!projectIds || !Array.isArray(projectIds) || projectIds.length === 0) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '请选择要更新的项目'
|
||||
});
|
||||
}
|
||||
|
||||
if (!['supervision', 'completed'].includes(status)) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '无效的项目状态'
|
||||
});
|
||||
}
|
||||
|
||||
await Project.update(
|
||||
{
|
||||
status,
|
||||
updatedBy: req.user?.id
|
||||
},
|
||||
{
|
||||
where: { id: { [Op.in]: projectIds } }
|
||||
}
|
||||
);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: `成功更新 ${projectIds.length} 个项目的状态`
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('批量更新项目状态失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '批量更新项目状态失败',
|
||||
error: process.env.NODE_ENV === 'development' ? error.message : undefined
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getProjects,
|
||||
getProjectById,
|
||||
createProject,
|
||||
updateProject,
|
||||
deleteProject,
|
||||
getProjectStats,
|
||||
batchUpdateStatus
|
||||
};
|
||||
573
bank-backend/controllers/supervisionTaskController.js
Normal file
573
bank-backend/controllers/supervisionTaskController.js
Normal file
@@ -0,0 +1,573 @@
|
||||
/**
|
||||
* 监管任务控制器
|
||||
* @file supervisionTaskController.js
|
||||
* @description 监管任务相关的API控制器
|
||||
*/
|
||||
const { SupervisionTask, User } = require('../models');
|
||||
const { Op } = require('sequelize');
|
||||
|
||||
// 获取监管任务列表
|
||||
const getSupervisionTasks = async (req, res) => {
|
||||
try {
|
||||
const {
|
||||
page = 1,
|
||||
limit = 10,
|
||||
search = '',
|
||||
supervisionStatus = '',
|
||||
dateRange = '',
|
||||
sortBy = 'createdAt',
|
||||
sortOrder = 'DESC'
|
||||
} = req.query;
|
||||
|
||||
const offset = (page - 1) * limit;
|
||||
|
||||
// 构建查询条件
|
||||
const where = {};
|
||||
|
||||
// 搜索条件
|
||||
if (search) {
|
||||
where[Op.or] = [
|
||||
{ applicationNumber: { [Op.like]: `%${search}%` } },
|
||||
{ contractNumber: { [Op.like]: `%${search}%` } },
|
||||
{ customerName: { [Op.like]: `%${search}%` } },
|
||||
{ productName: { [Op.like]: `%${search}%` } }
|
||||
];
|
||||
}
|
||||
|
||||
// 状态筛选
|
||||
if (supervisionStatus) {
|
||||
where.supervisionStatus = supervisionStatus;
|
||||
}
|
||||
|
||||
// 日期范围筛选
|
||||
if (dateRange) {
|
||||
const [startDate, endDate] = dateRange.split(',');
|
||||
if (startDate && endDate) {
|
||||
where.importTime = {
|
||||
[Op.between]: [new Date(startDate), new Date(endDate)]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 查询监管任务列表
|
||||
const { count, rows: tasks } = await SupervisionTask.findAndCountAll({
|
||||
where,
|
||||
include: [
|
||||
{
|
||||
model: User,
|
||||
as: 'creator',
|
||||
attributes: ['id', 'username', 'real_name']
|
||||
},
|
||||
{
|
||||
model: User,
|
||||
as: 'updater',
|
||||
attributes: ['id', 'username', 'real_name']
|
||||
}
|
||||
],
|
||||
order: [[sortBy, sortOrder.toUpperCase()]],
|
||||
limit: parseInt(limit),
|
||||
offset: parseInt(offset)
|
||||
});
|
||||
|
||||
// 计算分页信息
|
||||
const totalPages = Math.ceil(count / limit);
|
||||
const hasNextPage = page < totalPages;
|
||||
const hasPrevPage = page > 1;
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: '监管任务列表获取成功',
|
||||
data: {
|
||||
tasks,
|
||||
pagination: {
|
||||
total: count,
|
||||
currentPage: parseInt(page),
|
||||
pageSize: parseInt(limit),
|
||||
totalPages,
|
||||
hasNextPage,
|
||||
hasPrevPage
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取监管任务列表失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '获取监管任务列表失败',
|
||||
error: process.env.NODE_ENV === 'development' ? error.message : undefined
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 获取监管任务详情
|
||||
const getSupervisionTaskById = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const task = await SupervisionTask.findByPk(id, {
|
||||
include: [
|
||||
{
|
||||
model: User,
|
||||
as: 'creator',
|
||||
attributes: ['id', 'username', 'real_name']
|
||||
},
|
||||
{
|
||||
model: User,
|
||||
as: 'updater',
|
||||
attributes: ['id', 'username', 'real_name']
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
if (!task) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '监管任务不存在'
|
||||
});
|
||||
}
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: '监管任务详情获取成功',
|
||||
data: task
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取监管任务详情失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '获取监管任务详情失败',
|
||||
error: process.env.NODE_ENV === 'development' ? error.message : undefined
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 创建监管任务
|
||||
const createSupervisionTask = async (req, res) => {
|
||||
try {
|
||||
const {
|
||||
applicationNumber,
|
||||
contractNumber,
|
||||
productName,
|
||||
customerName,
|
||||
idType = 'id_card',
|
||||
idNumber,
|
||||
assetType = 'cattle',
|
||||
assetQuantity = 0,
|
||||
supervisionStatus = 'pending',
|
||||
startTime,
|
||||
endTime,
|
||||
loanAmount = 0,
|
||||
interestRate = 0,
|
||||
loanTerm = 12,
|
||||
supervisorName,
|
||||
supervisorPhone,
|
||||
farmAddress,
|
||||
remarks
|
||||
} = req.body;
|
||||
|
||||
// 验证必填字段
|
||||
const requiredFields = ['applicationNumber', 'contractNumber', 'productName', 'customerName', 'idNumber', 'startTime', 'endTime'];
|
||||
const missingFields = requiredFields.filter(field => !req.body[field]);
|
||||
|
||||
if (missingFields.length > 0) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: `请填写所有必填字段: ${missingFields.join(', ')}`
|
||||
});
|
||||
}
|
||||
|
||||
// 验证字段长度
|
||||
if (applicationNumber.length > 50) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '申请单号不能超过50个字符'
|
||||
});
|
||||
}
|
||||
|
||||
if (contractNumber.length > 50) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '放款合同编号不能超过50个字符'
|
||||
});
|
||||
}
|
||||
|
||||
if (productName.length > 100) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '产品名称不能超过100个字符'
|
||||
});
|
||||
}
|
||||
|
||||
if (customerName.length > 50) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '客户姓名不能超过50个字符'
|
||||
});
|
||||
}
|
||||
|
||||
// 验证数值字段
|
||||
if (assetQuantity < 0) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '监管生资数量不能为负数'
|
||||
});
|
||||
}
|
||||
|
||||
if (loanAmount < 0) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '贷款金额不能为负数'
|
||||
});
|
||||
}
|
||||
|
||||
if (interestRate < 0 || interestRate > 1) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '利率必须在0-1之间'
|
||||
});
|
||||
}
|
||||
|
||||
if (loanTerm < 0) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '贷款期限不能为负数'
|
||||
});
|
||||
}
|
||||
|
||||
// 验证状态和类型
|
||||
if (!['pending', 'supervising', 'completed', 'suspended'].includes(supervisionStatus)) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '监管状态无效'
|
||||
});
|
||||
}
|
||||
|
||||
if (!['id_card', 'passport', 'other'].includes(idType)) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '证件类型无效'
|
||||
});
|
||||
}
|
||||
|
||||
if (!['cattle', 'sheep', 'pig', 'poultry', 'other'].includes(assetType)) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '养殖生资种类无效'
|
||||
});
|
||||
}
|
||||
|
||||
// 验证日期格式和逻辑
|
||||
const startDate = new Date(startTime);
|
||||
const endDate = new Date(endTime);
|
||||
|
||||
if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '日期格式不正确'
|
||||
});
|
||||
}
|
||||
|
||||
if (startDate >= endDate) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '监管结束时间必须晚于开始时间'
|
||||
});
|
||||
}
|
||||
|
||||
// 检查申请单号和合同编号是否已存在
|
||||
const existingTask = await SupervisionTask.findOne({
|
||||
where: {
|
||||
[Op.or]: [
|
||||
{ applicationNumber },
|
||||
{ contractNumber }
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
if (existingTask) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: existingTask.applicationNumber === applicationNumber ?
|
||||
'申请单号已存在' : '放款合同编号已存在'
|
||||
});
|
||||
}
|
||||
|
||||
// 创建监管任务
|
||||
const task = await SupervisionTask.create({
|
||||
applicationNumber,
|
||||
contractNumber,
|
||||
productName,
|
||||
customerName,
|
||||
idType,
|
||||
idNumber,
|
||||
assetType,
|
||||
assetQuantity: parseInt(assetQuantity),
|
||||
supervisionStatus,
|
||||
startTime,
|
||||
endTime,
|
||||
loanAmount: parseFloat(loanAmount),
|
||||
interestRate: parseFloat(interestRate),
|
||||
loanTerm: parseInt(loanTerm),
|
||||
supervisorName,
|
||||
supervisorPhone,
|
||||
farmAddress,
|
||||
remarks,
|
||||
createdBy: req.user?.userId || req.user?.id,
|
||||
updatedBy: req.user?.userId || req.user?.id
|
||||
});
|
||||
|
||||
// 获取创建的任务详情(包含关联信息)
|
||||
const createdTask = await SupervisionTask.findByPk(task.id, {
|
||||
include: [
|
||||
{
|
||||
model: User,
|
||||
as: 'creator',
|
||||
attributes: ['id', 'username', 'real_name']
|
||||
},
|
||||
{
|
||||
model: User,
|
||||
as: 'updater',
|
||||
attributes: ['id', 'username', 'real_name']
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
res.status(201).json({
|
||||
success: true,
|
||||
data: createdTask,
|
||||
message: '监管任务创建成功'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('创建监管任务失败:', error);
|
||||
|
||||
// 处理数据库约束错误
|
||||
if (error.name === 'SequelizeValidationError') {
|
||||
const validationErrors = error.errors.map(err => err.message).join(', ');
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: `数据验证失败: ${validationErrors}`
|
||||
});
|
||||
}
|
||||
|
||||
if (error.name === 'SequelizeUniqueConstraintError') {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '申请单号或放款合同编号已存在'
|
||||
});
|
||||
}
|
||||
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '创建监管任务失败',
|
||||
error: process.env.NODE_ENV === 'development' ? error.message : undefined
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 更新监管任务
|
||||
const updateSupervisionTask = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const updateData = req.body;
|
||||
|
||||
// 验证日期
|
||||
if (updateData.startTime && updateData.endTime) {
|
||||
const startDate = new Date(updateData.startTime);
|
||||
const endDate = new Date(updateData.endTime);
|
||||
if (startDate >= endDate) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '监管结束时间必须晚于开始时间'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const task = await SupervisionTask.findByPk(id);
|
||||
|
||||
if (!task) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '监管任务不存在'
|
||||
});
|
||||
}
|
||||
|
||||
// 如果更新申请单号或合同编号,检查是否重复
|
||||
if (updateData.applicationNumber || updateData.contractNumber) {
|
||||
const whereCondition = { id: { [Op.ne]: id } };
|
||||
if (updateData.applicationNumber) {
|
||||
whereCondition.applicationNumber = updateData.applicationNumber;
|
||||
}
|
||||
if (updateData.contractNumber) {
|
||||
whereCondition.contractNumber = updateData.contractNumber;
|
||||
}
|
||||
|
||||
const existingTask = await SupervisionTask.findOne({ where: whereCondition });
|
||||
if (existingTask) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '申请单号或放款合同编号已存在'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await task.update({
|
||||
...updateData,
|
||||
updatedBy: req.user?.userId || req.user?.id
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
data: task,
|
||||
message: '监管任务更新成功'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('更新监管任务失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '更新监管任务失败',
|
||||
error: process.env.NODE_ENV === 'development' ? error.message : undefined
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 删除监管任务
|
||||
const deleteSupervisionTask = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const task = await SupervisionTask.findByPk(id);
|
||||
|
||||
if (!task) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '监管任务不存在'
|
||||
});
|
||||
}
|
||||
|
||||
await task.destroy();
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: '监管任务删除成功'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('删除监管任务失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '删除监管任务失败',
|
||||
error: process.env.NODE_ENV === 'development' ? error.message : undefined
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 获取监管任务统计
|
||||
const getSupervisionTaskStats = async (req, res) => {
|
||||
try {
|
||||
const total = await SupervisionTask.count();
|
||||
const pending = await SupervisionTask.count({ where: { supervisionStatus: 'pending' } });
|
||||
const supervising = await SupervisionTask.count({ where: { supervisionStatus: 'supervising' } });
|
||||
const completed = await SupervisionTask.count({ where: { supervisionStatus: 'completed' } });
|
||||
const suspended = await SupervisionTask.count({ where: { supervisionStatus: 'suspended' } });
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: '监管任务统计获取成功',
|
||||
data: {
|
||||
total,
|
||||
pending,
|
||||
supervising,
|
||||
completed,
|
||||
suspended
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取监管任务统计失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '获取监管任务统计失败',
|
||||
error: process.env.NODE_ENV === 'development' ? error.message : undefined
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 批量更新监管任务状态
|
||||
const batchUpdateStatus = async (req, res) => {
|
||||
try {
|
||||
const { ids, supervisionStatus } = req.body;
|
||||
|
||||
if (!Array.isArray(ids) || ids.length === 0 || !supervisionStatus) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '请求参数无效'
|
||||
});
|
||||
}
|
||||
|
||||
if (!['pending', 'supervising', 'completed', 'suspended'].includes(supervisionStatus)) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '监管状态无效'
|
||||
});
|
||||
}
|
||||
|
||||
const [updatedCount] = await SupervisionTask.update(
|
||||
{
|
||||
supervisionStatus,
|
||||
updatedBy: req.user?.userId || req.user?.id
|
||||
},
|
||||
{ where: { id: { [Op.in]: ids } } }
|
||||
);
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: `成功更新 ${updatedCount} 个监管任务状态`,
|
||||
data: { updatedCount }
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('批量更新监管任务状态失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '批量更新监管任务状态失败',
|
||||
error: process.env.NODE_ENV === 'development' ? error.message : undefined
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 批量删除监管任务
|
||||
const batchDeleteTasks = async (req, res) => {
|
||||
try {
|
||||
const { ids } = req.body;
|
||||
|
||||
if (!Array.isArray(ids) || ids.length === 0) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '请求参数无效'
|
||||
});
|
||||
}
|
||||
|
||||
const deletedCount = await SupervisionTask.destroy({
|
||||
where: { id: { [Op.in]: ids } }
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: `成功删除 ${deletedCount} 个监管任务`,
|
||||
data: { deletedCount }
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('批量删除监管任务失败:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '批量删除监管任务失败',
|
||||
error: process.env.NODE_ENV === 'development' ? error.message : undefined
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getSupervisionTasks,
|
||||
getSupervisionTaskById,
|
||||
createSupervisionTask,
|
||||
updateSupervisionTask,
|
||||
deleteSupervisionTask,
|
||||
getSupervisionTaskStats,
|
||||
batchUpdateStatus,
|
||||
batchDeleteTasks
|
||||
};
|
||||
403
bank-backend/docs/PROJECT_API.md
Normal file
403
bank-backend/docs/PROJECT_API.md
Normal file
@@ -0,0 +1,403 @@
|
||||
# 项目清单 API 接口文档
|
||||
|
||||
## 概述
|
||||
项目清单管理系统的后端API接口,提供项目的增删改查功能。
|
||||
|
||||
## 基础信息
|
||||
- **基础URL**: `http://localhost:5351/api/projects`
|
||||
- **认证方式**: Bearer Token
|
||||
- **内容类型**: `application/json`
|
||||
|
||||
## 接口列表
|
||||
|
||||
### 1. 创建项目
|
||||
**POST** `/api/projects`
|
||||
|
||||
#### 请求头
|
||||
```
|
||||
Authorization: Bearer <token>
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
#### 请求参数
|
||||
| 字段名 | 类型 | 必填 | 说明 | 示例 |
|
||||
|--------|------|------|------|------|
|
||||
| name | string | 是 | 项目名称,最大100字符 | "张洪彬养殖项目" |
|
||||
| farmName | string | 是 | 养殖场名称,最大200字符 | "张洪彬养殖场" |
|
||||
| supervisionObject | string | 是 | 监管对象 | "牛" |
|
||||
| supervisionPeriod | string | 是 | 监管周期 | "12个月" |
|
||||
| startTime | string | 是 | 起始时间,格式:YYYY-MM-DD | "2024-01-01" |
|
||||
| endTime | string | 是 | 结束时间,格式:YYYY-MM-DD | "2024-12-31" |
|
||||
| status | string | 否 | 项目状态,默认:supervision | "supervision" 或 "completed" |
|
||||
| supervisionQuantity | number | 否 | 监管数量,默认:0 | 100 |
|
||||
| supervisionAmount | number | 否 | 监管金额,默认:0.00 | 500000.00 |
|
||||
| earTag | number | 否 | 耳标数量,默认:0 | 50 |
|
||||
| collar | number | 否 | 项圈数量,默认:0 | 30 |
|
||||
| host | number | 否 | 主机数量,默认:0 | 20 |
|
||||
| loanOfficer | string | 否 | 贷款专员 | "张专员" |
|
||||
| description | string | 否 | 项目描述 | "这是一个测试项目" |
|
||||
|
||||
#### 请求示例
|
||||
```json
|
||||
{
|
||||
"name": "张洪彬养殖项目",
|
||||
"farmName": "张洪彬养殖场",
|
||||
"supervisionObject": "牛",
|
||||
"supervisionPeriod": "12个月",
|
||||
"startTime": "2024-01-01",
|
||||
"endTime": "2024-12-31",
|
||||
"status": "supervision",
|
||||
"supervisionQuantity": 100,
|
||||
"supervisionAmount": 500000.00,
|
||||
"earTag": 50,
|
||||
"collar": 30,
|
||||
"host": 20,
|
||||
"loanOfficer": "张专员",
|
||||
"description": "这是一个测试项目"
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
**成功响应 (201)**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "创建项目成功",
|
||||
"data": {
|
||||
"id": 9,
|
||||
"name": "张洪彬养殖项目",
|
||||
"status": "supervision",
|
||||
"farmName": "张洪彬养殖场",
|
||||
"supervisionObject": "牛",
|
||||
"supervisionQuantity": 100,
|
||||
"supervisionPeriod": "12个月",
|
||||
"supervisionAmount": "500000.00",
|
||||
"startTime": "2024-01-01",
|
||||
"endTime": "2024-12-31",
|
||||
"earTag": 50,
|
||||
"collar": 30,
|
||||
"host": 20,
|
||||
"loanOfficer": "张专员",
|
||||
"description": "这是一个测试项目",
|
||||
"createdBy": 1,
|
||||
"updatedBy": 1,
|
||||
"createdAt": "2024-12-20T10:30:00.000Z",
|
||||
"updatedAt": "2024-12-20T10:30:00.000Z",
|
||||
"creator": {
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
"real_name": "管理员"
|
||||
},
|
||||
"updater": {
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
"real_name": "管理员"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**错误响应 (400)**
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "请填写所有必填字段: name, farmName"
|
||||
}
|
||||
```
|
||||
|
||||
**错误响应 (400)**
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "项目名称已存在,请使用其他名称"
|
||||
}
|
||||
```
|
||||
|
||||
**错误响应 (400)**
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "结束时间必须晚于开始时间"
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 获取项目列表
|
||||
**GET** `/api/projects`
|
||||
|
||||
#### 查询参数
|
||||
| 参数名 | 类型 | 必填 | 说明 | 示例 |
|
||||
|--------|------|------|------|------|
|
||||
| page | number | 否 | 页码,默认:1 | 1 |
|
||||
| limit | number | 否 | 每页数量,默认:10 | 12 |
|
||||
| search | string | 否 | 搜索关键词 | "张洪彬" |
|
||||
| status | string | 否 | 状态筛选 | "supervision" 或 "completed" |
|
||||
| sortBy | string | 否 | 排序字段,默认:createdAt | "name" |
|
||||
| sortOrder | string | 否 | 排序方向,默认:DESC | "ASC" 或 "DESC" |
|
||||
|
||||
#### 请求示例
|
||||
```
|
||||
GET /api/projects?page=1&limit=12&search=张洪彬&status=supervision&sortBy=name&sortOrder=ASC
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "获取项目列表成功",
|
||||
"data": {
|
||||
"projects": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "张洪彬",
|
||||
"status": "completed",
|
||||
"farmName": "大数据中心",
|
||||
"supervisionObject": "牛",
|
||||
"supervisionQuantity": 100,
|
||||
"supervisionPeriod": "12个月",
|
||||
"supervisionAmount": "500000.00",
|
||||
"startTime": "2024-01-01",
|
||||
"endTime": "2024-12-31",
|
||||
"earTag": 50,
|
||||
"collar": 30,
|
||||
"host": 20,
|
||||
"loanOfficer": "张专员",
|
||||
"description": "项目描述",
|
||||
"createdAt": "2024-12-20T10:30:00.000Z",
|
||||
"updatedAt": "2024-12-20T10:30:00.000Z",
|
||||
"creator": {
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
"real_name": "管理员"
|
||||
},
|
||||
"updater": {
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
"real_name": "管理员"
|
||||
}
|
||||
}
|
||||
],
|
||||
"pagination": {
|
||||
"total": 8,
|
||||
"currentPage": 1,
|
||||
"pageSize": 12,
|
||||
"totalPages": 1,
|
||||
"hasNextPage": false,
|
||||
"hasPrevPage": false
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 获取项目详情
|
||||
**GET** `/api/projects/:id`
|
||||
|
||||
#### 路径参数
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| id | number | 是 | 项目ID |
|
||||
|
||||
#### 响应示例
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "获取项目详情成功",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"name": "张洪彬",
|
||||
"status": "completed",
|
||||
"farmName": "大数据中心",
|
||||
"supervisionObject": "牛",
|
||||
"supervisionQuantity": 100,
|
||||
"supervisionPeriod": "12个月",
|
||||
"supervisionAmount": "500000.00",
|
||||
"startTime": "2024-01-01",
|
||||
"endTime": "2024-12-31",
|
||||
"earTag": 50,
|
||||
"collar": 30,
|
||||
"host": 20,
|
||||
"loanOfficer": "张专员",
|
||||
"description": "项目描述",
|
||||
"createdAt": "2024-12-20T10:30:00.000Z",
|
||||
"updatedAt": "2024-12-20T10:30:00.000Z",
|
||||
"creator": {
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
"real_name": "管理员"
|
||||
},
|
||||
"updater": {
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
"real_name": "管理员"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 更新项目
|
||||
**PUT** `/api/projects/:id`
|
||||
|
||||
#### 请求参数
|
||||
与创建项目相同,所有字段都是可选的。
|
||||
|
||||
#### 响应示例
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "项目更新成功",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"name": "更新后的项目名称",
|
||||
"status": "completed",
|
||||
// ... 其他字段
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 删除项目
|
||||
**DELETE** `/api/projects/:id`
|
||||
|
||||
#### 响应示例
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "项目删除成功"
|
||||
}
|
||||
```
|
||||
|
||||
### 6. 获取项目统计
|
||||
**GET** `/api/projects/stats`
|
||||
|
||||
#### 响应示例
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "项目统计获取成功",
|
||||
"data": {
|
||||
"total": 8,
|
||||
"supervision": 3,
|
||||
"completed": 5
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 7. 批量更新项目状态
|
||||
**PUT** `/api/projects/batch/status`
|
||||
|
||||
#### 请求参数
|
||||
```json
|
||||
{
|
||||
"ids": [1, 2, 3],
|
||||
"status": "completed"
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "成功更新 3 个项目状态",
|
||||
"data": {
|
||||
"updatedCount": 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 错误码说明
|
||||
|
||||
| 状态码 | 说明 |
|
||||
|--------|------|
|
||||
| 200 | 请求成功 |
|
||||
| 201 | 创建成功 |
|
||||
| 400 | 请求参数错误 |
|
||||
| 401 | 未授权,需要登录 |
|
||||
| 403 | 禁止访问,权限不足 |
|
||||
| 404 | 资源不存在 |
|
||||
| 500 | 服务器内部错误 |
|
||||
|
||||
## 数据验证规则
|
||||
|
||||
### 必填字段验证
|
||||
- `name`: 项目名称,不能为空
|
||||
- `farmName`: 养殖场名称,不能为空
|
||||
- `supervisionObject`: 监管对象,不能为空
|
||||
- `supervisionPeriod`: 监管周期,不能为空
|
||||
- `startTime`: 起始时间,不能为空
|
||||
- `endTime`: 结束时间,不能为空
|
||||
|
||||
### 字段长度限制
|
||||
- `name`: 最大100个字符
|
||||
- `farmName`: 最大200个字符
|
||||
- `supervisionObject`: 最大50个字符
|
||||
- `supervisionPeriod`: 最大50个字符
|
||||
- `loanOfficer`: 最大100个字符
|
||||
|
||||
### 数值字段验证
|
||||
- `supervisionQuantity`: 不能为负数
|
||||
- `supervisionAmount`: 不能为负数
|
||||
- `earTag`: 不能为负数
|
||||
- `collar`: 不能为负数
|
||||
- `host`: 不能为负数
|
||||
|
||||
### 日期验证
|
||||
- `startTime` 和 `endTime` 必须是有效的日期格式 (YYYY-MM-DD)
|
||||
- `endTime` 必须晚于 `startTime`
|
||||
|
||||
### 状态验证
|
||||
- `status` 只能是 "supervision" 或 "completed"
|
||||
|
||||
## 使用示例
|
||||
|
||||
### JavaScript (axios)
|
||||
```javascript
|
||||
// 创建项目
|
||||
const createProject = async (projectData) => {
|
||||
try {
|
||||
const response = await axios.post('/api/projects', projectData, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('创建项目失败:', error.response.data);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// 获取项目列表
|
||||
const getProjects = async (params = {}) => {
|
||||
try {
|
||||
const response = await axios.get('/api/projects', {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
},
|
||||
params
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('获取项目列表失败:', error.response.data);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### cURL
|
||||
```bash
|
||||
# 创建项目
|
||||
curl -X POST http://localhost:5351/api/projects \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "测试项目",
|
||||
"farmName": "测试养殖场",
|
||||
"supervisionObject": "牛",
|
||||
"supervisionPeriod": "12个月",
|
||||
"startTime": "2024-01-01",
|
||||
"endTime": "2024-12-31"
|
||||
}'
|
||||
|
||||
# 获取项目列表
|
||||
curl -X GET "http://localhost:5351/api/projects?page=1&limit=10" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN"
|
||||
```
|
||||
459
bank-backend/docs/SUPERVISION_TASKS_API.md
Normal file
459
bank-backend/docs/SUPERVISION_TASKS_API.md
Normal file
@@ -0,0 +1,459 @@
|
||||
# 监管任务 API 接口文档
|
||||
|
||||
## 概述
|
||||
监管任务管理系统的后端API接口,提供监管任务的增删改查功能。
|
||||
|
||||
## 基础信息
|
||||
- **基础URL**: `http://localhost:5351/api/supervision-tasks`
|
||||
- **认证方式**: Bearer Token
|
||||
- **内容类型**: `application/json`
|
||||
|
||||
## 接口列表
|
||||
|
||||
### 1. 创建监管任务
|
||||
**POST** `/api/supervision-tasks`
|
||||
|
||||
#### 请求头
|
||||
```
|
||||
Authorization: Bearer <token>
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
#### 请求参数
|
||||
| 字段名 | 类型 | 必填 | 说明 | 示例 |
|
||||
|--------|------|------|------|------|
|
||||
| applicationNumber | string | 是 | 申请单号,最大50字符,唯一 | "APP001" |
|
||||
| contractNumber | string | 是 | 放款合同编号,最大50字符,唯一 | "CONTRACT001" |
|
||||
| productName | string | 是 | 产品名称,最大100字符 | "农业贷款产品A" |
|
||||
| customerName | string | 是 | 客户姓名,最大50字符 | "张三" |
|
||||
| idType | string | 是 | 证件类型 | "id_card" (身份证), "passport" (护照), "other" (其他) |
|
||||
| idNumber | string | 是 | 证件号码,最大50字符 | "110101199001011234" |
|
||||
| assetType | string | 是 | 养殖生资种类 | "cattle" (牛), "sheep" (羊), "pig" (猪), "poultry" (家禽), "other" (其他) |
|
||||
| assetQuantity | number | 是 | 监管生资数量,非负数 | 10 |
|
||||
| startTime | string | 是 | 监管起始时间,格式:YYYY-MM-DD | "2024-01-15" |
|
||||
| endTime | string | 是 | 监管结束时间,格式:YYYY-MM-DD | "2024-12-15" |
|
||||
| supervisionStatus | string | 否 | 监管状态,默认:pending | "pending", "supervising", "completed", "suspended" |
|
||||
| loanAmount | number | 否 | 贷款金额,默认:0 | 500000.00 |
|
||||
| interestRate | number | 否 | 利率,默认:0,范围:0-1 | 0.0650 |
|
||||
| loanTerm | number | 否 | 贷款期限(月),默认:12 | 12 |
|
||||
| supervisorName | string | 否 | 监管员姓名,最大50字符 | "李监管员" |
|
||||
| supervisorPhone | string | 否 | 监管员电话,最大20字符 | "13800138001" |
|
||||
| farmAddress | string | 否 | 养殖场地址,最大200字符 | "北京市朝阳区某某养殖场" |
|
||||
| remarks | string | 否 | 备注 | "重点监管项目,需要定期检查" |
|
||||
|
||||
#### 请求示例
|
||||
```json
|
||||
{
|
||||
"applicationNumber": "APP001",
|
||||
"contractNumber": "CONTRACT001",
|
||||
"productName": "农业贷款产品A",
|
||||
"customerName": "张三",
|
||||
"idType": "id_card",
|
||||
"idNumber": "110101199001011234",
|
||||
"assetType": "cattle",
|
||||
"assetQuantity": 10,
|
||||
"supervisionStatus": "pending",
|
||||
"startTime": "2024-01-15",
|
||||
"endTime": "2024-12-15",
|
||||
"loanAmount": 500000.00,
|
||||
"interestRate": 0.0650,
|
||||
"loanTerm": 12,
|
||||
"supervisorName": "李监管员",
|
||||
"supervisorPhone": "13800138001",
|
||||
"farmAddress": "北京市朝阳区某某养殖场",
|
||||
"remarks": "重点监管项目,需要定期检查"
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
**成功响应 (201)**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "监管任务创建成功",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"applicationNumber": "APP001",
|
||||
"contractNumber": "CONTRACT001",
|
||||
"productName": "农业贷款产品A",
|
||||
"customerName": "张三",
|
||||
"idType": "id_card",
|
||||
"idNumber": "110101199001011234",
|
||||
"assetType": "cattle",
|
||||
"assetQuantity": 10,
|
||||
"supervisionStatus": "pending",
|
||||
"importTime": "2024-12-20T10:30:00.000Z",
|
||||
"startTime": "2024-01-15",
|
||||
"endTime": "2024-12-15",
|
||||
"loanAmount": "500000.00",
|
||||
"interestRate": "0.0650",
|
||||
"loanTerm": 12,
|
||||
"supervisorName": "李监管员",
|
||||
"supervisorPhone": "13800138001",
|
||||
"farmAddress": "北京市朝阳区某某养殖场",
|
||||
"remarks": "重点监管项目,需要定期检查",
|
||||
"createdBy": 1,
|
||||
"updatedBy": 1,
|
||||
"createdAt": "2024-12-20T10:30:00.000Z",
|
||||
"updatedAt": "2024-12-20T10:30:00.000Z",
|
||||
"creator": {
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
"real_name": "管理员"
|
||||
},
|
||||
"updater": {
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
"real_name": "管理员"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 获取监管任务列表
|
||||
**GET** `/api/supervision-tasks`
|
||||
|
||||
#### 查询参数
|
||||
| 参数名 | 类型 | 必填 | 说明 | 示例 |
|
||||
|--------|------|------|------|------|
|
||||
| page | number | 否 | 页码,默认:1 | 1 |
|
||||
| limit | number | 否 | 每页数量,默认:10 | 10 |
|
||||
| search | string | 否 | 搜索关键词(申请单号、合同编号、客户姓名、产品名称) | "张三" |
|
||||
| supervisionStatus | string | 否 | 状态筛选 | "pending", "supervising", "completed", "suspended" |
|
||||
| dateRange | string | 否 | 日期范围筛选,格式:startDate,endDate | "2024-01-01,2024-12-31" |
|
||||
| sortBy | string | 否 | 排序字段,默认:createdAt | "applicationNumber", "customerName", "supervisionStatus" |
|
||||
| sortOrder | string | 否 | 排序方向,默认:DESC | "ASC", "DESC" |
|
||||
|
||||
#### 请求示例
|
||||
```
|
||||
GET /api/supervision-tasks?page=1&limit=10&search=张三&supervisionStatus=supervising&dateRange=2024-01-01,2024-12-31&sortBy=customerName&sortOrder=ASC
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "监管任务列表获取成功",
|
||||
"data": {
|
||||
"tasks": [
|
||||
{
|
||||
"id": 1,
|
||||
"applicationNumber": "APP001",
|
||||
"contractNumber": "CONTRACT001",
|
||||
"productName": "农业贷款产品A",
|
||||
"customerName": "张三",
|
||||
"idType": "id_card",
|
||||
"idNumber": "110101199001011234",
|
||||
"assetType": "cattle",
|
||||
"assetQuantity": 10,
|
||||
"supervisionStatus": "supervising",
|
||||
"importTime": "2024-01-15T10:30:00.000Z",
|
||||
"startTime": "2024-01-15",
|
||||
"endTime": "2024-12-15",
|
||||
"loanAmount": "500000.00",
|
||||
"interestRate": "0.0650",
|
||||
"loanTerm": 12,
|
||||
"supervisorName": "李监管员",
|
||||
"supervisorPhone": "13800138001",
|
||||
"farmAddress": "北京市朝阳区某某养殖场",
|
||||
"remarks": "重点监管项目,需要定期检查",
|
||||
"createdAt": "2024-12-20T10:30:00.000Z",
|
||||
"updatedAt": "2024-12-20T10:30:00.000Z",
|
||||
"creator": {
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
"real_name": "管理员"
|
||||
},
|
||||
"updater": {
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
"real_name": "管理员"
|
||||
}
|
||||
}
|
||||
],
|
||||
"pagination": {
|
||||
"total": 8,
|
||||
"currentPage": 1,
|
||||
"pageSize": 10,
|
||||
"totalPages": 1,
|
||||
"hasNextPage": false,
|
||||
"hasPrevPage": false
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 获取监管任务详情
|
||||
**GET** `/api/supervision-tasks/:id`
|
||||
|
||||
#### 路径参数
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| id | number | 是 | 监管任务ID |
|
||||
|
||||
#### 响应示例
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "监管任务详情获取成功",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"applicationNumber": "APP001",
|
||||
"contractNumber": "CONTRACT001",
|
||||
"productName": "农业贷款产品A",
|
||||
"customerName": "张三",
|
||||
"idType": "id_card",
|
||||
"idNumber": "110101199001011234",
|
||||
"assetType": "cattle",
|
||||
"assetQuantity": 10,
|
||||
"supervisionStatus": "supervising",
|
||||
"importTime": "2024-01-15T10:30:00.000Z",
|
||||
"startTime": "2024-01-15",
|
||||
"endTime": "2024-12-15",
|
||||
"loanAmount": "500000.00",
|
||||
"interestRate": "0.0650",
|
||||
"loanTerm": 12,
|
||||
"supervisorName": "李监管员",
|
||||
"supervisorPhone": "13800138001",
|
||||
"farmAddress": "北京市朝阳区某某养殖场",
|
||||
"remarks": "重点监管项目,需要定期检查",
|
||||
"createdAt": "2024-12-20T10:30:00.000Z",
|
||||
"updatedAt": "2024-12-20T10:30:00.000Z",
|
||||
"creator": {
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
"real_name": "管理员"
|
||||
},
|
||||
"updater": {
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
"real_name": "管理员"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 更新监管任务
|
||||
**PUT** `/api/supervision-tasks/:id`
|
||||
|
||||
#### 请求参数
|
||||
与创建监管任务相同,所有字段都是可选的。
|
||||
|
||||
#### 响应示例
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "监管任务更新成功",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"applicationNumber": "APP001",
|
||||
"contractNumber": "CONTRACT001",
|
||||
"productName": "农业贷款产品A",
|
||||
"customerName": "张三",
|
||||
"supervisionStatus": "supervising",
|
||||
"remarks": "更新后的备注信息",
|
||||
"updatedAt": "2024-12-20T11:00:00.000Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 删除监管任务
|
||||
**DELETE** `/api/supervision-tasks/:id`
|
||||
|
||||
#### 响应示例
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "监管任务删除成功"
|
||||
}
|
||||
```
|
||||
|
||||
### 6. 获取监管任务统计
|
||||
**GET** `/api/supervision-tasks/stats`
|
||||
|
||||
#### 响应示例
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "监管任务统计获取成功",
|
||||
"data": {
|
||||
"total": 8,
|
||||
"pending": 2,
|
||||
"supervising": 3,
|
||||
"completed": 2,
|
||||
"suspended": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 7. 批量更新监管任务状态
|
||||
**PUT** `/api/supervision-tasks/batch/status`
|
||||
|
||||
#### 请求参数
|
||||
```json
|
||||
{
|
||||
"ids": [1, 2, 3],
|
||||
"supervisionStatus": "completed"
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "成功更新 3 个监管任务状态",
|
||||
"data": {
|
||||
"updatedCount": 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 8. 批量删除监管任务
|
||||
**DELETE** `/api/supervision-tasks/batch`
|
||||
|
||||
#### 请求参数
|
||||
```json
|
||||
{
|
||||
"ids": [1, 2, 3]
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "成功删除 3 个监管任务",
|
||||
"data": {
|
||||
"deletedCount": 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 错误码说明
|
||||
|
||||
| 状态码 | 说明 |
|
||||
|--------|------|
|
||||
| 200 | 请求成功 |
|
||||
| 201 | 创建成功 |
|
||||
| 400 | 请求参数错误 |
|
||||
| 401 | 未授权,需要登录 |
|
||||
| 403 | 禁止访问,权限不足 |
|
||||
| 404 | 资源不存在 |
|
||||
| 500 | 服务器内部错误 |
|
||||
|
||||
## 数据验证规则
|
||||
|
||||
### 必填字段验证
|
||||
- `applicationNumber`: 申请单号,不能为空,最大50字符,唯一
|
||||
- `contractNumber`: 放款合同编号,不能为空,最大50字符,唯一
|
||||
- `productName`: 产品名称,不能为空,最大100字符
|
||||
- `customerName`: 客户姓名,不能为空,最大50字符
|
||||
- `idNumber`: 证件号码,不能为空,最大50字符
|
||||
- `startTime`: 监管起始时间,不能为空
|
||||
- `endTime`: 监管结束时间,不能为空
|
||||
|
||||
### 枚举值验证
|
||||
- `idType`: 只能是 "id_card", "passport", "other"
|
||||
- `assetType`: 只能是 "cattle", "sheep", "pig", "poultry", "other"
|
||||
- `supervisionStatus`: 只能是 "pending", "supervising", "completed", "suspended"
|
||||
|
||||
### 数值字段验证
|
||||
- `assetQuantity`: 不能为负数
|
||||
- `loanAmount`: 不能为负数
|
||||
- `interestRate`: 必须在0-1之间
|
||||
- `loanTerm`: 不能为负数
|
||||
|
||||
### 日期验证
|
||||
- `startTime` 和 `endTime` 必须是有效的日期格式 (YYYY-MM-DD)
|
||||
- `endTime` 必须晚于 `startTime`
|
||||
|
||||
## 使用示例
|
||||
|
||||
### JavaScript (axios)
|
||||
```javascript
|
||||
// 创建监管任务
|
||||
const createSupervisionTask = async (taskData) => {
|
||||
try {
|
||||
const response = await axios.post('/api/supervision-tasks', taskData, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('创建监管任务失败:', error.response.data);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// 获取监管任务列表
|
||||
const getSupervisionTasks = async (params = {}) => {
|
||||
try {
|
||||
const response = await axios.get('/api/supervision-tasks', {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
},
|
||||
params
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('获取监管任务列表失败:', error.response.data);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### cURL
|
||||
```bash
|
||||
# 创建监管任务
|
||||
curl -X POST http://localhost:5351/api/supervision-tasks \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"applicationNumber": "APP001",
|
||||
"contractNumber": "CONTRACT001",
|
||||
"productName": "农业贷款产品A",
|
||||
"customerName": "张三",
|
||||
"idType": "id_card",
|
||||
"idNumber": "110101199001011234",
|
||||
"assetType": "cattle",
|
||||
"assetQuantity": 10,
|
||||
"startTime": "2024-01-15",
|
||||
"endTime": "2024-12-15"
|
||||
}'
|
||||
|
||||
# 获取监管任务列表
|
||||
curl -X GET "http://localhost:5351/api/supervision-tasks?page=1&limit=10" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN"
|
||||
```
|
||||
|
||||
## 数据库表结构
|
||||
|
||||
### supervision_tasks 表
|
||||
| 字段名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| id | INTEGER | 主键,自增 |
|
||||
| applicationNumber | VARCHAR(50) | 申请单号,唯一 |
|
||||
| contractNumber | VARCHAR(50) | 放款合同编号,唯一 |
|
||||
| productName | VARCHAR(100) | 产品名称 |
|
||||
| customerName | VARCHAR(50) | 客户姓名 |
|
||||
| idType | ENUM | 证件类型 |
|
||||
| idNumber | VARCHAR(50) | 证件号码 |
|
||||
| assetType | ENUM | 养殖生资种类 |
|
||||
| assetQuantity | INTEGER | 监管生资数量 |
|
||||
| supervisionStatus | ENUM | 监管状态 |
|
||||
| importTime | DATETIME | 任务导入时间 |
|
||||
| startTime | DATE | 监管起始时间 |
|
||||
| endTime | DATE | 监管结束时间 |
|
||||
| loanAmount | DECIMAL(15,2) | 贷款金额 |
|
||||
| interestRate | DECIMAL(5,4) | 利率 |
|
||||
| loanTerm | INTEGER | 贷款期限(月) |
|
||||
| supervisorName | VARCHAR(50) | 监管员姓名 |
|
||||
| supervisorPhone | VARCHAR(20) | 监管员电话 |
|
||||
| farmAddress | VARCHAR(200) | 养殖场地址 |
|
||||
| remarks | TEXT | 备注 |
|
||||
| createdBy | INTEGER | 创建人ID |
|
||||
| updatedBy | INTEGER | 更新人ID |
|
||||
| createdAt | DATETIME | 创建时间 |
|
||||
| updatedAt | DATETIME | 更新时间 |
|
||||
121
bank-backend/migrations/20241220000002-create-projects.js
Normal file
121
bank-backend/migrations/20241220000002-create-projects.js
Normal file
@@ -0,0 +1,121 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
async up(queryInterface, Sequelize) {
|
||||
await queryInterface.createTable('projects', {
|
||||
id: {
|
||||
type: Sequelize.INTEGER,
|
||||
primaryKey: true,
|
||||
autoIncrement: true,
|
||||
allowNull: false
|
||||
},
|
||||
name: {
|
||||
type: Sequelize.STRING(100),
|
||||
allowNull: false,
|
||||
comment: '项目名称'
|
||||
},
|
||||
status: {
|
||||
type: Sequelize.ENUM('supervision', 'completed'),
|
||||
allowNull: false,
|
||||
defaultValue: 'supervision',
|
||||
comment: '项目状态:supervision-监管中,completed-已结项'
|
||||
},
|
||||
farmName: {
|
||||
type: Sequelize.STRING(200),
|
||||
allowNull: false,
|
||||
comment: '养殖场名称'
|
||||
},
|
||||
supervisionObject: {
|
||||
type: Sequelize.STRING(50),
|
||||
allowNull: false,
|
||||
comment: '监管对象'
|
||||
},
|
||||
supervisionQuantity: {
|
||||
type: Sequelize.INTEGER,
|
||||
allowNull: false,
|
||||
defaultValue: 0,
|
||||
comment: '监管数量'
|
||||
},
|
||||
supervisionPeriod: {
|
||||
type: Sequelize.STRING(50),
|
||||
allowNull: false,
|
||||
comment: '监管周期'
|
||||
},
|
||||
supervisionAmount: {
|
||||
type: Sequelize.DECIMAL(15, 2),
|
||||
allowNull: false,
|
||||
defaultValue: 0.00,
|
||||
comment: '监管金额'
|
||||
},
|
||||
startTime: {
|
||||
type: Sequelize.DATEONLY,
|
||||
allowNull: false,
|
||||
comment: '起始时间'
|
||||
},
|
||||
endTime: {
|
||||
type: Sequelize.DATEONLY,
|
||||
allowNull: false,
|
||||
comment: '结束时间'
|
||||
},
|
||||
earTag: {
|
||||
type: Sequelize.INTEGER,
|
||||
allowNull: false,
|
||||
defaultValue: 0,
|
||||
comment: '耳标数量'
|
||||
},
|
||||
collar: {
|
||||
type: Sequelize.INTEGER,
|
||||
allowNull: false,
|
||||
defaultValue: 0,
|
||||
comment: '项圈数量'
|
||||
},
|
||||
host: {
|
||||
type: Sequelize.INTEGER,
|
||||
allowNull: false,
|
||||
defaultValue: 0,
|
||||
comment: '主机数量'
|
||||
},
|
||||
loanOfficer: {
|
||||
type: Sequelize.STRING(100),
|
||||
allowNull: true,
|
||||
comment: '贷款专员'
|
||||
},
|
||||
description: {
|
||||
type: Sequelize.TEXT,
|
||||
allowNull: true,
|
||||
comment: '项目描述'
|
||||
},
|
||||
createdBy: {
|
||||
type: Sequelize.INTEGER,
|
||||
allowNull: true,
|
||||
comment: '创建人ID'
|
||||
},
|
||||
updatedBy: {
|
||||
type: Sequelize.INTEGER,
|
||||
allowNull: true,
|
||||
comment: '更新人ID'
|
||||
},
|
||||
createdAt: {
|
||||
type: Sequelize.DATE,
|
||||
allowNull: false,
|
||||
defaultValue: Sequelize.NOW
|
||||
},
|
||||
updatedAt: {
|
||||
type: Sequelize.DATE,
|
||||
allowNull: false,
|
||||
defaultValue: Sequelize.NOW
|
||||
}
|
||||
});
|
||||
|
||||
// 添加索引
|
||||
await queryInterface.addIndex('projects', ['status']);
|
||||
await queryInterface.addIndex('projects', ['farmName']);
|
||||
await queryInterface.addIndex('projects', ['createdBy']);
|
||||
await queryInterface.addIndex('projects', ['startTime']);
|
||||
await queryInterface.addIndex('projects', ['endTime']);
|
||||
},
|
||||
|
||||
async down(queryInterface, Sequelize) {
|
||||
await queryInterface.dropTable('projects');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,152 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
async up(queryInterface, Sequelize) {
|
||||
await queryInterface.createTable('supervision_tasks', {
|
||||
id: {
|
||||
type: Sequelize.INTEGER,
|
||||
primaryKey: true,
|
||||
autoIncrement: true,
|
||||
allowNull: false
|
||||
},
|
||||
applicationNumber: {
|
||||
type: Sequelize.STRING(50),
|
||||
allowNull: false,
|
||||
unique: true,
|
||||
comment: '申请单号'
|
||||
},
|
||||
contractNumber: {
|
||||
type: Sequelize.STRING(50),
|
||||
allowNull: false,
|
||||
unique: true,
|
||||
comment: '放款合同编号'
|
||||
},
|
||||
productName: {
|
||||
type: Sequelize.STRING(100),
|
||||
allowNull: false,
|
||||
comment: '产品名称'
|
||||
},
|
||||
customerName: {
|
||||
type: Sequelize.STRING(50),
|
||||
allowNull: false,
|
||||
comment: '客户姓名'
|
||||
},
|
||||
idType: {
|
||||
type: Sequelize.ENUM('id_card', 'passport', 'other'),
|
||||
allowNull: false,
|
||||
defaultValue: 'id_card',
|
||||
comment: '证件类型:id_card-身份证,passport-护照,other-其他'
|
||||
},
|
||||
idNumber: {
|
||||
type: Sequelize.STRING(50),
|
||||
allowNull: false,
|
||||
comment: '证件号码'
|
||||
},
|
||||
assetType: {
|
||||
type: Sequelize.ENUM('cattle', 'sheep', 'pig', 'poultry', 'other'),
|
||||
allowNull: false,
|
||||
defaultValue: 'cattle',
|
||||
comment: '养殖生资种类:cattle-牛,sheep-羊,pig-猪,poultry-家禽,other-其他'
|
||||
},
|
||||
assetQuantity: {
|
||||
type: Sequelize.INTEGER,
|
||||
allowNull: false,
|
||||
defaultValue: 0,
|
||||
comment: '监管生资数量'
|
||||
},
|
||||
supervisionStatus: {
|
||||
type: Sequelize.ENUM('pending', 'supervising', 'completed', 'suspended'),
|
||||
allowNull: false,
|
||||
defaultValue: 'pending',
|
||||
comment: '监管状态:pending-待监管,supervising-监管中,completed-已完成,suspended-已暂停'
|
||||
},
|
||||
importTime: {
|
||||
type: Sequelize.DATE,
|
||||
allowNull: false,
|
||||
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
|
||||
comment: '任务导入时间'
|
||||
},
|
||||
startTime: {
|
||||
type: Sequelize.DATEONLY,
|
||||
allowNull: false,
|
||||
comment: '监管起始时间'
|
||||
},
|
||||
endTime: {
|
||||
type: Sequelize.DATEONLY,
|
||||
allowNull: false,
|
||||
comment: '监管结束时间'
|
||||
},
|
||||
loanAmount: {
|
||||
type: Sequelize.DECIMAL(15, 2),
|
||||
allowNull: true,
|
||||
defaultValue: 0.00,
|
||||
comment: '贷款金额'
|
||||
},
|
||||
interestRate: {
|
||||
type: Sequelize.DECIMAL(5, 4),
|
||||
allowNull: true,
|
||||
defaultValue: 0.0000,
|
||||
comment: '利率'
|
||||
},
|
||||
loanTerm: {
|
||||
type: Sequelize.INTEGER,
|
||||
allowNull: true,
|
||||
defaultValue: 12,
|
||||
comment: '贷款期限(月)'
|
||||
},
|
||||
supervisorName: {
|
||||
type: Sequelize.STRING(50),
|
||||
allowNull: true,
|
||||
comment: '监管员姓名'
|
||||
},
|
||||
supervisorPhone: {
|
||||
type: Sequelize.STRING(20),
|
||||
allowNull: true,
|
||||
comment: '监管员电话'
|
||||
},
|
||||
farmAddress: {
|
||||
type: Sequelize.STRING(200),
|
||||
allowNull: true,
|
||||
comment: '养殖场地址'
|
||||
},
|
||||
remarks: {
|
||||
type: Sequelize.TEXT,
|
||||
allowNull: true,
|
||||
comment: '备注'
|
||||
},
|
||||
createdBy: {
|
||||
type: Sequelize.INTEGER,
|
||||
allowNull: true,
|
||||
comment: '创建人ID'
|
||||
},
|
||||
updatedBy: {
|
||||
type: Sequelize.INTEGER,
|
||||
allowNull: true,
|
||||
comment: '更新人ID'
|
||||
},
|
||||
createdAt: {
|
||||
type: Sequelize.DATE,
|
||||
allowNull: false,
|
||||
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP')
|
||||
},
|
||||
updatedAt: {
|
||||
type: Sequelize.DATE,
|
||||
allowNull: false,
|
||||
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP')
|
||||
}
|
||||
});
|
||||
|
||||
// 添加索引
|
||||
await queryInterface.addIndex('supervision_tasks', ['applicationNumber']);
|
||||
await queryInterface.addIndex('supervision_tasks', ['contractNumber']);
|
||||
await queryInterface.addIndex('supervision_tasks', ['customerName']);
|
||||
await queryInterface.addIndex('supervision_tasks', ['supervisionStatus']);
|
||||
await queryInterface.addIndex('supervision_tasks', ['createdBy']);
|
||||
await queryInterface.addIndex('supervision_tasks', ['startTime']);
|
||||
await queryInterface.addIndex('supervision_tasks', ['endTime']);
|
||||
},
|
||||
|
||||
async down(queryInterface, Sequelize) {
|
||||
await queryInterface.dropTable('supervision_tasks');
|
||||
}
|
||||
};
|
||||
119
bank-backend/models/Project.js
Normal file
119
bank-backend/models/Project.js
Normal file
@@ -0,0 +1,119 @@
|
||||
const { DataTypes } = require('sequelize');
|
||||
const { sequelize } = require('../config/database');
|
||||
|
||||
const Project = sequelize.define('Project', {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
primaryKey: true,
|
||||
autoIncrement: true
|
||||
},
|
||||
name: {
|
||||
type: DataTypes.STRING(100),
|
||||
allowNull: false,
|
||||
comment: '项目名称'
|
||||
},
|
||||
status: {
|
||||
type: DataTypes.ENUM('supervision', 'completed'),
|
||||
allowNull: false,
|
||||
defaultValue: 'supervision',
|
||||
comment: '项目状态:supervision-监管中,completed-已结项'
|
||||
},
|
||||
farmName: {
|
||||
type: DataTypes.STRING(200),
|
||||
allowNull: false,
|
||||
comment: '养殖场名称'
|
||||
},
|
||||
supervisionObject: {
|
||||
type: DataTypes.STRING(50),
|
||||
allowNull: false,
|
||||
comment: '监管对象'
|
||||
},
|
||||
supervisionQuantity: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
defaultValue: 0,
|
||||
comment: '监管数量'
|
||||
},
|
||||
supervisionPeriod: {
|
||||
type: DataTypes.STRING(50),
|
||||
allowNull: false,
|
||||
comment: '监管周期'
|
||||
},
|
||||
supervisionAmount: {
|
||||
type: DataTypes.DECIMAL(15, 2),
|
||||
allowNull: false,
|
||||
defaultValue: 0.00,
|
||||
comment: '监管金额'
|
||||
},
|
||||
startTime: {
|
||||
type: DataTypes.DATEONLY,
|
||||
allowNull: false,
|
||||
comment: '起始时间'
|
||||
},
|
||||
endTime: {
|
||||
type: DataTypes.DATEONLY,
|
||||
allowNull: false,
|
||||
comment: '结束时间'
|
||||
},
|
||||
earTag: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
defaultValue: 0,
|
||||
comment: '耳标数量'
|
||||
},
|
||||
collar: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
defaultValue: 0,
|
||||
comment: '项圈数量'
|
||||
},
|
||||
host: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
defaultValue: 0,
|
||||
comment: '主机数量'
|
||||
},
|
||||
loanOfficer: {
|
||||
type: DataTypes.STRING(100),
|
||||
allowNull: true,
|
||||
comment: '贷款专员'
|
||||
},
|
||||
description: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
comment: '项目描述'
|
||||
},
|
||||
createdBy: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
comment: '创建人ID'
|
||||
},
|
||||
updatedBy: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
comment: '更新人ID'
|
||||
}
|
||||
}, {
|
||||
tableName: 'projects',
|
||||
timestamps: true,
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt',
|
||||
comment: '项目清单表'
|
||||
});
|
||||
|
||||
// 定义关联关系
|
||||
Project.associate = (models) => {
|
||||
// 项目与用户关联(创建人)
|
||||
Project.belongsTo(models.User, {
|
||||
foreignKey: 'createdBy',
|
||||
as: 'creator'
|
||||
});
|
||||
|
||||
// 项目与用户关联(更新人)
|
||||
Project.belongsTo(models.User, {
|
||||
foreignKey: 'updatedBy',
|
||||
as: 'updater'
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = Project;
|
||||
166
bank-backend/models/SupervisionTask.js
Normal file
166
bank-backend/models/SupervisionTask.js
Normal file
@@ -0,0 +1,166 @@
|
||||
/**
|
||||
* 监管任务模型
|
||||
* @file SupervisionTask.js
|
||||
* @description 监管任务数据模型定义
|
||||
*/
|
||||
const { DataTypes } = require('sequelize');
|
||||
const BaseModel = require('./BaseModel');
|
||||
const { sequelize } = require('../config/database');
|
||||
|
||||
class SupervisionTask extends BaseModel {}
|
||||
|
||||
SupervisionTask.init({
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
primaryKey: true,
|
||||
autoIncrement: true
|
||||
},
|
||||
applicationNumber: {
|
||||
type: DataTypes.STRING(50),
|
||||
allowNull: false,
|
||||
unique: true,
|
||||
comment: '申请单号'
|
||||
},
|
||||
contractNumber: {
|
||||
type: DataTypes.STRING(50),
|
||||
allowNull: false,
|
||||
unique: true,
|
||||
comment: '放款合同编号'
|
||||
},
|
||||
productName: {
|
||||
type: DataTypes.STRING(100),
|
||||
allowNull: false,
|
||||
comment: '产品名称'
|
||||
},
|
||||
customerName: {
|
||||
type: DataTypes.STRING(50),
|
||||
allowNull: false,
|
||||
comment: '客户姓名'
|
||||
},
|
||||
idType: {
|
||||
type: DataTypes.ENUM('id_card', 'passport', 'other'),
|
||||
allowNull: false,
|
||||
defaultValue: 'id_card',
|
||||
comment: '证件类型:id_card-身份证,passport-护照,other-其他'
|
||||
},
|
||||
idNumber: {
|
||||
type: DataTypes.STRING(50),
|
||||
allowNull: false,
|
||||
comment: '证件号码'
|
||||
},
|
||||
assetType: {
|
||||
type: DataTypes.ENUM('cattle', 'sheep', 'pig', 'poultry', 'other'),
|
||||
allowNull: false,
|
||||
defaultValue: 'cattle',
|
||||
comment: '养殖生资种类:cattle-牛,sheep-羊,pig-猪,poultry-家禽,other-其他'
|
||||
},
|
||||
assetQuantity: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
defaultValue: 0,
|
||||
comment: '监管生资数量'
|
||||
},
|
||||
supervisionStatus: {
|
||||
type: DataTypes.ENUM('pending', 'supervising', 'completed', 'suspended'),
|
||||
allowNull: false,
|
||||
defaultValue: 'pending',
|
||||
comment: '监管状态:pending-待监管,supervising-监管中,completed-已完成,suspended-已暂停'
|
||||
},
|
||||
importTime: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false,
|
||||
defaultValue: DataTypes.NOW,
|
||||
comment: '任务导入时间'
|
||||
},
|
||||
startTime: {
|
||||
type: DataTypes.DATEONLY,
|
||||
allowNull: false,
|
||||
comment: '监管起始时间'
|
||||
},
|
||||
endTime: {
|
||||
type: DataTypes.DATEONLY,
|
||||
allowNull: false,
|
||||
comment: '监管结束时间'
|
||||
},
|
||||
loanAmount: {
|
||||
type: DataTypes.DECIMAL(15, 2),
|
||||
allowNull: true,
|
||||
defaultValue: 0.00,
|
||||
comment: '贷款金额'
|
||||
},
|
||||
interestRate: {
|
||||
type: DataTypes.DECIMAL(5, 4),
|
||||
allowNull: true,
|
||||
defaultValue: 0.0000,
|
||||
comment: '利率'
|
||||
},
|
||||
loanTerm: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
defaultValue: 12,
|
||||
comment: '贷款期限(月)'
|
||||
},
|
||||
supervisorName: {
|
||||
type: DataTypes.STRING(50),
|
||||
allowNull: true,
|
||||
comment: '监管员姓名'
|
||||
},
|
||||
supervisorPhone: {
|
||||
type: DataTypes.STRING(20),
|
||||
allowNull: true,
|
||||
comment: '监管员电话'
|
||||
},
|
||||
farmAddress: {
|
||||
type: DataTypes.STRING(200),
|
||||
allowNull: true,
|
||||
comment: '养殖场地址'
|
||||
},
|
||||
remarks: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
comment: '备注'
|
||||
},
|
||||
createdBy: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
comment: '创建人ID'
|
||||
},
|
||||
updatedBy: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
comment: '更新人ID'
|
||||
},
|
||||
createdAt: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false,
|
||||
defaultValue: DataTypes.NOW
|
||||
},
|
||||
updatedAt: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false,
|
||||
defaultValue: DataTypes.NOW
|
||||
}
|
||||
}, {
|
||||
sequelize,
|
||||
modelName: 'SupervisionTask',
|
||||
tableName: 'supervision_tasks',
|
||||
timestamps: true,
|
||||
underscored: true,
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt',
|
||||
comment: '监管任务表'
|
||||
});
|
||||
|
||||
// 定义关联关系
|
||||
SupervisionTask.associate = (models) => {
|
||||
SupervisionTask.belongsTo(models.User, {
|
||||
foreignKey: 'createdBy',
|
||||
as: 'creator'
|
||||
});
|
||||
SupervisionTask.belongsTo(models.User, {
|
||||
foreignKey: 'updatedBy',
|
||||
as: 'updater'
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = SupervisionTask;
|
||||
@@ -15,6 +15,8 @@ const Employee = require('./Employee');
|
||||
const Department = require('./Department');
|
||||
const Position = require('./Position');
|
||||
const Report = require('./Report');
|
||||
const Project = require('./Project');
|
||||
const SupervisionTask = require('./SupervisionTask');
|
||||
|
||||
// 定义模型关联关系
|
||||
|
||||
@@ -91,6 +93,54 @@ User.hasMany(Report, {
|
||||
as: 'reports'
|
||||
});
|
||||
|
||||
// 项目与用户关联(创建人)
|
||||
Project.belongsTo(User, {
|
||||
foreignKey: 'createdBy',
|
||||
as: 'creator',
|
||||
targetKey: 'id'
|
||||
});
|
||||
|
||||
User.hasMany(Project, {
|
||||
foreignKey: 'createdBy',
|
||||
as: 'createdProjects'
|
||||
});
|
||||
|
||||
// 项目与用户关联(更新人)
|
||||
Project.belongsTo(User, {
|
||||
foreignKey: 'updatedBy',
|
||||
as: 'updater',
|
||||
targetKey: 'id'
|
||||
});
|
||||
|
||||
User.hasMany(Project, {
|
||||
foreignKey: 'updatedBy',
|
||||
as: 'updatedProjects'
|
||||
});
|
||||
|
||||
// 监管任务与用户关联(创建人)
|
||||
SupervisionTask.belongsTo(User, {
|
||||
foreignKey: 'createdBy',
|
||||
as: 'creator',
|
||||
targetKey: 'id'
|
||||
});
|
||||
|
||||
User.hasMany(SupervisionTask, {
|
||||
foreignKey: 'createdBy',
|
||||
as: 'createdSupervisionTasks'
|
||||
});
|
||||
|
||||
// 监管任务与用户关联(更新人)
|
||||
SupervisionTask.belongsTo(User, {
|
||||
foreignKey: 'updatedBy',
|
||||
as: 'updater',
|
||||
targetKey: 'id'
|
||||
});
|
||||
|
||||
User.hasMany(SupervisionTask, {
|
||||
foreignKey: 'updatedBy',
|
||||
as: 'updatedSupervisionTasks'
|
||||
});
|
||||
|
||||
// 导出所有模型和数据库实例
|
||||
module.exports = {
|
||||
sequelize,
|
||||
@@ -102,5 +152,7 @@ module.exports = {
|
||||
Employee,
|
||||
Department,
|
||||
Position,
|
||||
Report
|
||||
Report,
|
||||
Project,
|
||||
SupervisionTask
|
||||
};
|
||||
37
bank-backend/routes/projects.js
Normal file
37
bank-backend/routes/projects.js
Normal file
@@ -0,0 +1,37 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const projectController = require('../controllers/projectController');
|
||||
const { authMiddleware } = require('../middleware/auth');
|
||||
|
||||
// 应用认证中间件到所有路由
|
||||
router.use(authMiddleware);
|
||||
|
||||
// 获取项目列表
|
||||
// GET /api/projects
|
||||
router.get('/', projectController.getProjects);
|
||||
|
||||
// 获取项目统计
|
||||
// GET /api/projects/stats
|
||||
router.get('/stats', projectController.getProjectStats);
|
||||
|
||||
// 获取项目详情
|
||||
// GET /api/projects/:id
|
||||
router.get('/:id', projectController.getProjectById);
|
||||
|
||||
// 创建项目
|
||||
// POST /api/projects
|
||||
router.post('/', projectController.createProject);
|
||||
|
||||
// 更新项目
|
||||
// PUT /api/projects/:id
|
||||
router.put('/:id', projectController.updateProject);
|
||||
|
||||
// 删除项目
|
||||
// DELETE /api/projects/:id
|
||||
router.delete('/:id', projectController.deleteProject);
|
||||
|
||||
// 批量更新项目状态
|
||||
// PUT /api/projects/batch/status
|
||||
router.put('/batch/status', projectController.batchUpdateStatus);
|
||||
|
||||
module.exports = router;
|
||||
41
bank-backend/routes/supervisionTasks.js
Normal file
41
bank-backend/routes/supervisionTasks.js
Normal file
@@ -0,0 +1,41 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const supervisionTaskController = require('../controllers/supervisionTaskController');
|
||||
const { authMiddleware } = require('../middleware/auth');
|
||||
|
||||
// 应用认证中间件到所有路由
|
||||
router.use(authMiddleware);
|
||||
|
||||
// 获取监管任务列表
|
||||
// GET /api/supervision-tasks
|
||||
router.get('/', supervisionTaskController.getSupervisionTasks);
|
||||
|
||||
// 获取监管任务统计
|
||||
// GET /api/supervision-tasks/stats
|
||||
router.get('/stats', supervisionTaskController.getSupervisionTaskStats);
|
||||
|
||||
// 获取监管任务详情
|
||||
// GET /api/supervision-tasks/:id
|
||||
router.get('/:id', supervisionTaskController.getSupervisionTaskById);
|
||||
|
||||
// 创建监管任务
|
||||
// POST /api/supervision-tasks
|
||||
router.post('/', supervisionTaskController.createSupervisionTask);
|
||||
|
||||
// 更新监管任务
|
||||
// PUT /api/supervision-tasks/:id
|
||||
router.put('/:id', supervisionTaskController.updateSupervisionTask);
|
||||
|
||||
// 删除监管任务
|
||||
// DELETE /api/supervision-tasks/:id
|
||||
router.delete('/:id', supervisionTaskController.deleteSupervisionTask);
|
||||
|
||||
// 批量更新监管任务状态
|
||||
// PUT /api/supervision-tasks/batch/status
|
||||
router.put('/batch/status', supervisionTaskController.batchUpdateStatus);
|
||||
|
||||
// 批量删除监管任务
|
||||
// DELETE /api/supervision-tasks/batch
|
||||
router.delete('/batch', supervisionTaskController.batchDeleteTasks);
|
||||
|
||||
module.exports = router;
|
||||
200
bank-backend/scripts/seed-projects.js
Normal file
200
bank-backend/scripts/seed-projects.js
Normal file
@@ -0,0 +1,200 @@
|
||||
const { Project, User } = require('../models');
|
||||
const { sequelize } = require('../config/database');
|
||||
|
||||
// 项目测试数据
|
||||
const projectsData = [
|
||||
{
|
||||
name: '张洪彬',
|
||||
status: 'completed',
|
||||
farmName: '大数据中心',
|
||||
supervisionObject: '牛',
|
||||
supervisionQuantity: 10,
|
||||
supervisionPeriod: '23天',
|
||||
supervisionAmount: 10000.00,
|
||||
startTime: '2024-02-21',
|
||||
endTime: '2024-03-15',
|
||||
earTag: 0,
|
||||
collar: 0,
|
||||
host: 0,
|
||||
loanOfficer: 'mapleaf',
|
||||
description: '大数据中心养殖项目'
|
||||
},
|
||||
{
|
||||
name: '田小平',
|
||||
status: 'completed',
|
||||
farmName: '139****5685_养殖场',
|
||||
supervisionObject: '牛',
|
||||
supervisionQuantity: 0,
|
||||
supervisionPeriod: '0天',
|
||||
supervisionAmount: 0.00,
|
||||
startTime: '2022-12-12',
|
||||
endTime: '2023-12-12',
|
||||
earTag: 0,
|
||||
collar: 0,
|
||||
host: 0,
|
||||
loanOfficer: '',
|
||||
description: '田小平养殖场项目'
|
||||
},
|
||||
{
|
||||
name: '杜宝民',
|
||||
status: 'completed',
|
||||
farmName: '杜宝民养殖场',
|
||||
supervisionObject: '牛',
|
||||
supervisionQuantity: 1,
|
||||
supervisionPeriod: '20天',
|
||||
supervisionAmount: 1000000.00,
|
||||
startTime: '2023-05-08',
|
||||
endTime: '2028-05-08',
|
||||
earTag: 0,
|
||||
collar: 0,
|
||||
host: 0,
|
||||
loanOfficer: 'mapleaf',
|
||||
description: '杜宝民养殖场长期项目'
|
||||
},
|
||||
{
|
||||
name: '满良',
|
||||
status: 'completed',
|
||||
farmName: '满良养殖场',
|
||||
supervisionObject: '牛',
|
||||
supervisionQuantity: 30,
|
||||
supervisionPeriod: '365天',
|
||||
supervisionAmount: 420000.00,
|
||||
startTime: '2023-01-01',
|
||||
endTime: '2024-01-01',
|
||||
earTag: 0,
|
||||
collar: 0,
|
||||
host: 0,
|
||||
loanOfficer: 'mapleaf',
|
||||
description: '满良养殖场年度项目'
|
||||
},
|
||||
{
|
||||
name: '敖日布仁琴',
|
||||
status: 'supervision',
|
||||
farmName: '敖日布仁琴养殖场',
|
||||
supervisionObject: '牛',
|
||||
supervisionQuantity: 38,
|
||||
supervisionPeriod: '1827天',
|
||||
supervisionAmount: 530000.00,
|
||||
startTime: '2019-01-01',
|
||||
endTime: '2024-01-01',
|
||||
earTag: 0,
|
||||
collar: 0,
|
||||
host: 0,
|
||||
loanOfficer: 'mapleaf',
|
||||
description: '敖日布仁琴养殖场长期监管项目'
|
||||
},
|
||||
{
|
||||
name: '那顺乌日图',
|
||||
status: 'supervision',
|
||||
farmName: '那顺乌日图养殖场',
|
||||
supervisionObject: '牛',
|
||||
supervisionQuantity: 36,
|
||||
supervisionPeriod: '1827天',
|
||||
supervisionAmount: 500000.00,
|
||||
startTime: '2019-01-01',
|
||||
endTime: '2024-01-01',
|
||||
earTag: 0,
|
||||
collar: 0,
|
||||
host: 0,
|
||||
loanOfficer: 'mapleaf',
|
||||
description: '那顺乌日图养殖场长期监管项目'
|
||||
},
|
||||
{
|
||||
name: '巴特尔',
|
||||
status: 'supervision',
|
||||
farmName: '巴特尔养殖场',
|
||||
supervisionObject: '牛',
|
||||
supervisionQuantity: 41,
|
||||
supervisionPeriod: '1827天',
|
||||
supervisionAmount: 570000.00,
|
||||
startTime: '2019-01-01',
|
||||
endTime: '2024-01-01',
|
||||
earTag: 0,
|
||||
collar: 0,
|
||||
host: 0,
|
||||
loanOfficer: 'mapleaf',
|
||||
description: '巴特尔养殖场长期监管项目'
|
||||
},
|
||||
{
|
||||
name: '王五',
|
||||
status: 'completed',
|
||||
farmName: '王五养殖场',
|
||||
supervisionObject: '牛',
|
||||
supervisionQuantity: 50,
|
||||
supervisionPeriod: '365天',
|
||||
supervisionAmount: 700000.00,
|
||||
startTime: '2023-01-01',
|
||||
endTime: '2024-01-01',
|
||||
earTag: 0,
|
||||
collar: 0,
|
||||
host: 0,
|
||||
loanOfficer: 'mapleaf',
|
||||
description: '王五养殖场年度项目'
|
||||
}
|
||||
];
|
||||
|
||||
async function seedProjects() {
|
||||
try {
|
||||
console.log('开始创建项目测试数据...');
|
||||
|
||||
// 测试数据库连接
|
||||
await sequelize.authenticate();
|
||||
console.log('✅ 数据库连接成功');
|
||||
|
||||
// 查找管理员用户作为创建人
|
||||
const adminUser = await User.findOne({ where: { username: 'admin' } });
|
||||
const createdBy = adminUser ? adminUser.id : null;
|
||||
|
||||
// 清空现有项目数据
|
||||
await Project.destroy({ where: {} });
|
||||
console.log('✅ 清空现有项目数据');
|
||||
|
||||
// 创建项目数据
|
||||
for (const projectData of projectsData) {
|
||||
await Project.create({
|
||||
...projectData,
|
||||
createdBy: createdBy,
|
||||
updatedBy: createdBy
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`✅ 成功创建 ${projectsData.length} 个项目`);
|
||||
|
||||
// 验证数据
|
||||
const projectCount = await Project.count();
|
||||
console.log(`📊 数据库中现有项目数量: ${projectCount}`);
|
||||
|
||||
// 显示统计信息
|
||||
const supervisionCount = await Project.count({ where: { status: 'supervision' } });
|
||||
const completedCount = await Project.count({ where: { status: 'completed' } });
|
||||
const totalAmount = await Project.sum('supervisionAmount');
|
||||
const totalQuantity = await Project.sum('supervisionQuantity');
|
||||
|
||||
console.log('\n📈 项目统计信息:');
|
||||
console.log(` 监管中项目: ${supervisionCount}`);
|
||||
console.log(` 已结项项目: ${completedCount}`);
|
||||
console.log(` 总监管金额: ${totalAmount?.toFixed(2) || 0} 元`);
|
||||
console.log(` 总监管数量: ${totalQuantity || 0} 头`);
|
||||
|
||||
console.log('\n🎉 项目数据创建完成!');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 创建项目数据失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果直接运行此脚本
|
||||
if (require.main === module) {
|
||||
seedProjects()
|
||||
.then(() => {
|
||||
console.log('✅ 脚本执行完成');
|
||||
process.exit(0);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('❌ 脚本执行失败:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = seedProjects;
|
||||
261
bank-backend/scripts/seed-supervision-tasks.js
Normal file
261
bank-backend/scripts/seed-supervision-tasks.js
Normal file
@@ -0,0 +1,261 @@
|
||||
/**
|
||||
* 监管任务测试数据种子文件
|
||||
* @file seed-supervision-tasks.js
|
||||
* @description 为监管任务表添加测试数据
|
||||
*/
|
||||
const { sequelize, SupervisionTask, User } = require('../models');
|
||||
|
||||
async function seedSupervisionTasks() {
|
||||
try {
|
||||
console.log('🌱 开始添加监管任务测试数据...');
|
||||
|
||||
// 检查是否已有数据
|
||||
const existingCount = await SupervisionTask.count();
|
||||
if (existingCount > 0) {
|
||||
console.log(`⚠️ 监管任务表已有 ${existingCount} 条数据,跳过种子数据添加`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取管理员用户ID
|
||||
const adminUser = await User.findOne({ where: { username: 'admin' } });
|
||||
if (!adminUser) {
|
||||
console.log('❌ 未找到管理员用户,请先运行用户种子数据');
|
||||
return;
|
||||
}
|
||||
|
||||
const adminId = adminUser.id;
|
||||
|
||||
// 监管任务测试数据
|
||||
const supervisionTasks = [
|
||||
{
|
||||
applicationNumber: 'APP001',
|
||||
contractNumber: 'CONTRACT001',
|
||||
productName: '农业贷款产品A',
|
||||
customerName: '张三',
|
||||
idType: 'id_card',
|
||||
idNumber: '110101199001011234',
|
||||
assetType: 'cattle',
|
||||
assetQuantity: 10,
|
||||
supervisionStatus: 'supervising',
|
||||
importTime: new Date('2024-01-15 10:30:00'),
|
||||
startTime: '2024-01-15',
|
||||
endTime: '2024-12-15',
|
||||
loanAmount: 500000.00,
|
||||
interestRate: 0.0650,
|
||||
loanTerm: 12,
|
||||
supervisorName: '李监管员',
|
||||
supervisorPhone: '13800138001',
|
||||
farmAddress: '北京市朝阳区某某养殖场',
|
||||
remarks: '重点监管项目,需要定期检查',
|
||||
createdBy: adminId,
|
||||
updatedBy: adminId
|
||||
},
|
||||
{
|
||||
applicationNumber: 'APP002',
|
||||
contractNumber: 'CONTRACT002',
|
||||
productName: '农业贷款产品B',
|
||||
customerName: '李四',
|
||||
idType: 'id_card',
|
||||
idNumber: '110101199002021234',
|
||||
assetType: 'sheep',
|
||||
assetQuantity: 20,
|
||||
supervisionStatus: 'pending',
|
||||
importTime: new Date('2024-01-16 14:20:00'),
|
||||
startTime: '2024-01-16',
|
||||
endTime: '2024-12-16',
|
||||
loanAmount: 300000.00,
|
||||
interestRate: 0.0600,
|
||||
loanTerm: 12,
|
||||
supervisorName: '王监管员',
|
||||
supervisorPhone: '13800138002',
|
||||
farmAddress: '北京市海淀区某某农场',
|
||||
remarks: '新申请项目,待开始监管',
|
||||
createdBy: adminId,
|
||||
updatedBy: adminId
|
||||
},
|
||||
{
|
||||
applicationNumber: 'APP003',
|
||||
contractNumber: 'CONTRACT003',
|
||||
productName: '农业贷款产品C',
|
||||
customerName: '王五',
|
||||
idType: 'id_card',
|
||||
idNumber: '110101199003031234',
|
||||
assetType: 'pig',
|
||||
assetQuantity: 15,
|
||||
supervisionStatus: 'completed',
|
||||
importTime: new Date('2024-01-10 09:15:00'),
|
||||
startTime: '2024-01-10',
|
||||
endTime: '2024-01-20',
|
||||
loanAmount: 200000.00,
|
||||
interestRate: 0.0550,
|
||||
loanTerm: 6,
|
||||
supervisorName: '赵监管员',
|
||||
supervisorPhone: '13800138003',
|
||||
farmAddress: '北京市丰台区某某猪场',
|
||||
remarks: '监管任务已完成,客户还款正常',
|
||||
createdBy: adminId,
|
||||
updatedBy: adminId
|
||||
},
|
||||
{
|
||||
applicationNumber: 'APP004',
|
||||
contractNumber: 'CONTRACT004',
|
||||
productName: '农业贷款产品D',
|
||||
customerName: '赵六',
|
||||
idType: 'id_card',
|
||||
idNumber: '110101199004041234',
|
||||
assetType: 'poultry',
|
||||
assetQuantity: 50,
|
||||
supervisionStatus: 'supervising',
|
||||
importTime: new Date('2024-01-20 11:45:00'),
|
||||
startTime: '2024-01-20',
|
||||
endTime: '2024-06-20',
|
||||
loanAmount: 150000.00,
|
||||
interestRate: 0.0700,
|
||||
loanTerm: 6,
|
||||
supervisorName: '孙监管员',
|
||||
supervisorPhone: '13800138004',
|
||||
farmAddress: '北京市通州区某某鸡场',
|
||||
remarks: '家禽养殖项目,需要特别关注防疫情况',
|
||||
createdBy: adminId,
|
||||
updatedBy: adminId
|
||||
},
|
||||
{
|
||||
applicationNumber: 'APP005',
|
||||
contractNumber: 'CONTRACT005',
|
||||
productName: '农业贷款产品E',
|
||||
customerName: '孙七',
|
||||
idType: 'id_card',
|
||||
idNumber: '110101199005051234',
|
||||
assetType: 'cattle',
|
||||
assetQuantity: 25,
|
||||
supervisionStatus: 'suspended',
|
||||
importTime: new Date('2024-01-25 16:30:00'),
|
||||
startTime: '2024-01-25',
|
||||
endTime: '2024-12-25',
|
||||
loanAmount: 800000.00,
|
||||
interestRate: 0.0625,
|
||||
loanTerm: 18,
|
||||
supervisorName: '周监管员',
|
||||
supervisorPhone: '13800138005',
|
||||
farmAddress: '北京市昌平区某某牧场',
|
||||
remarks: '因客户原因暂停监管,等待进一步通知',
|
||||
createdBy: adminId,
|
||||
updatedBy: adminId
|
||||
},
|
||||
{
|
||||
applicationNumber: 'APP006',
|
||||
contractNumber: 'CONTRACT006',
|
||||
productName: '农业贷款产品F',
|
||||
customerName: '周八',
|
||||
idType: 'passport',
|
||||
idNumber: 'P123456789',
|
||||
assetType: 'other',
|
||||
assetQuantity: 30,
|
||||
supervisionStatus: 'supervising',
|
||||
importTime: new Date('2024-02-01 08:20:00'),
|
||||
startTime: '2024-02-01',
|
||||
endTime: '2024-08-01',
|
||||
loanAmount: 400000.00,
|
||||
interestRate: 0.0680,
|
||||
loanTerm: 6,
|
||||
supervisorName: '吴监管员',
|
||||
supervisorPhone: '13800138006',
|
||||
farmAddress: '北京市顺义区某某特种养殖场',
|
||||
remarks: '特种养殖项目,需要专业监管',
|
||||
createdBy: adminId,
|
||||
updatedBy: adminId
|
||||
},
|
||||
{
|
||||
applicationNumber: 'APP007',
|
||||
contractNumber: 'CONTRACT007',
|
||||
productName: '农业贷款产品G',
|
||||
customerName: '吴九',
|
||||
idType: 'id_card',
|
||||
idNumber: '110101199007071234',
|
||||
assetType: 'sheep',
|
||||
assetQuantity: 40,
|
||||
supervisionStatus: 'pending',
|
||||
importTime: new Date('2024-02-05 13:10:00'),
|
||||
startTime: '2024-02-05',
|
||||
endTime: '2024-12-05',
|
||||
loanAmount: 600000.00,
|
||||
interestRate: 0.0590,
|
||||
loanTerm: 12,
|
||||
supervisorName: '郑监管员',
|
||||
supervisorPhone: '13800138007',
|
||||
farmAddress: '北京市房山区某某羊场',
|
||||
remarks: '大规模羊群养殖,需要加强监管',
|
||||
createdBy: adminId,
|
||||
updatedBy: adminId
|
||||
},
|
||||
{
|
||||
applicationNumber: 'APP008',
|
||||
contractNumber: 'CONTRACT008',
|
||||
productName: '农业贷款产品H',
|
||||
customerName: '郑十',
|
||||
idType: 'id_card',
|
||||
idNumber: '110101199008081234',
|
||||
assetType: 'pig',
|
||||
assetQuantity: 35,
|
||||
supervisionStatus: 'completed',
|
||||
importTime: new Date('2024-01-05 15:45:00'),
|
||||
startTime: '2024-01-05',
|
||||
endTime: '2024-03-05',
|
||||
loanAmount: 350000.00,
|
||||
interestRate: 0.0575,
|
||||
loanTerm: 3,
|
||||
supervisorName: '冯监管员',
|
||||
supervisorPhone: '13800138008',
|
||||
farmAddress: '北京市大兴区某某养猪场',
|
||||
remarks: '短期养殖项目,已顺利完成监管',
|
||||
createdBy: adminId,
|
||||
updatedBy: adminId
|
||||
}
|
||||
];
|
||||
|
||||
// 批量创建监管任务
|
||||
await SupervisionTask.bulkCreate(supervisionTasks);
|
||||
|
||||
console.log(`✅ 成功添加 ${supervisionTasks.length} 条监管任务测试数据`);
|
||||
|
||||
// 显示统计信息
|
||||
const stats = await SupervisionTask.findAll({
|
||||
attributes: [
|
||||
'supervisionStatus',
|
||||
[sequelize.fn('COUNT', sequelize.col('id')), 'count']
|
||||
],
|
||||
group: ['supervisionStatus'],
|
||||
raw: true
|
||||
});
|
||||
|
||||
console.log('📊 监管任务状态统计:');
|
||||
stats.forEach(stat => {
|
||||
const statusNames = {
|
||||
'pending': '待监管',
|
||||
'supervising': '监管中',
|
||||
'completed': '已完成',
|
||||
'suspended': '已暂停'
|
||||
};
|
||||
console.log(` ${statusNames[stat.supervisionStatus] || stat.supervisionStatus}: ${stat.count} 条`);
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 添加监管任务测试数据失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果直接运行此文件
|
||||
if (require.main === module) {
|
||||
seedSupervisionTasks()
|
||||
.then(() => {
|
||||
console.log('🎉 监管任务种子数据添加完成');
|
||||
process.exit(0);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('💥 监管任务种子数据添加失败:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = seedSupervisionTasks;
|
||||
60
bank-backend/scripts/setup-projects-simple.js
Normal file
60
bank-backend/scripts/setup-projects-simple.js
Normal file
@@ -0,0 +1,60 @@
|
||||
const { sequelize } = require('../config/database');
|
||||
const { Project } = require('../models');
|
||||
const seedProjects = require('./seed-projects');
|
||||
|
||||
async function setupProjectsSimple() {
|
||||
try {
|
||||
console.log('🚀 开始设置项目清单功能...\n');
|
||||
|
||||
// 1. 测试数据库连接
|
||||
console.log('1️⃣ 测试数据库连接...');
|
||||
await sequelize.authenticate();
|
||||
console.log('✅ 数据库连接成功\n');
|
||||
|
||||
// 2. 同步项目模型(创建表)
|
||||
console.log('2️⃣ 创建项目表...');
|
||||
await Project.sync({ force: false }); // force: false 表示如果表已存在则不删除
|
||||
console.log('✅ 项目表创建成功\n');
|
||||
|
||||
// 3. 创建项目测试数据
|
||||
console.log('3️⃣ 创建项目测试数据...');
|
||||
await seedProjects();
|
||||
console.log('✅ 项目测试数据创建完成\n');
|
||||
|
||||
// 4. 验证数据
|
||||
console.log('4️⃣ 验证项目数据...');
|
||||
const projectCount = await Project.count();
|
||||
const supervisionCount = await Project.count({ where: { status: 'supervision' } });
|
||||
const completedCount = await Project.count({ where: { status: 'completed' } });
|
||||
|
||||
console.log(` 总项目数: ${projectCount}`);
|
||||
console.log(` 监管中项目: ${supervisionCount}`);
|
||||
console.log(` 已结项项目: ${completedCount}`);
|
||||
console.log('✅ 项目数据验证完成\n');
|
||||
|
||||
console.log('🎉 项目清单功能设置完成!');
|
||||
console.log('📝 接下来可以:');
|
||||
console.log(' 1. 启动后端服务器: npm start');
|
||||
console.log(' 2. 运行API测试: node test-projects-api.js');
|
||||
console.log(' 3. 在前端访问项目清单页面');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 设置项目清单功能失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果直接运行此脚本
|
||||
if (require.main === module) {
|
||||
setupProjectsSimple()
|
||||
.then(() => {
|
||||
console.log('✅ 脚本执行完成');
|
||||
process.exit(0);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('❌ 脚本执行失败:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = setupProjectsSimple;
|
||||
79
bank-backend/scripts/setup-projects.js
Normal file
79
bank-backend/scripts/setup-projects.js
Normal file
@@ -0,0 +1,79 @@
|
||||
const { sequelize } = require('../config/database');
|
||||
const seedProjects = require('./seed-projects');
|
||||
|
||||
async function setupProjects() {
|
||||
try {
|
||||
console.log('🚀 开始设置项目清单功能...\n');
|
||||
|
||||
// 1. 测试数据库连接
|
||||
console.log('1️⃣ 测试数据库连接...');
|
||||
await sequelize.authenticate();
|
||||
console.log('✅ 数据库连接成功\n');
|
||||
|
||||
// 2. 运行项目表迁移
|
||||
console.log('2️⃣ 运行项目表迁移...');
|
||||
try {
|
||||
const { QueryInterface } = require('sequelize');
|
||||
const queryInterface = sequelize.getQueryInterface();
|
||||
|
||||
// 检查表是否已存在
|
||||
const tableExists = await queryInterface.showAllTables().then(tables =>
|
||||
tables.includes('projects')
|
||||
);
|
||||
|
||||
if (!tableExists) {
|
||||
// 运行迁移
|
||||
const migration = require('../migrations/20241220000002-create-projects');
|
||||
await migration.up(queryInterface, sequelize);
|
||||
console.log('✅ 项目表创建成功\n');
|
||||
} else {
|
||||
console.log('✅ 项目表已存在\n');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ 项目表迁移失败:', error.message);
|
||||
throw error;
|
||||
}
|
||||
|
||||
// 3. 创建项目测试数据
|
||||
console.log('3️⃣ 创建项目测试数据...');
|
||||
await seedProjects();
|
||||
console.log('✅ 项目测试数据创建完成\n');
|
||||
|
||||
// 4. 验证数据
|
||||
console.log('4️⃣ 验证项目数据...');
|
||||
const { Project } = require('../models');
|
||||
const projectCount = await Project.count();
|
||||
const supervisionCount = await Project.count({ where: { status: 'supervision' } });
|
||||
const completedCount = await Project.count({ where: { status: 'completed' } });
|
||||
|
||||
console.log(` 总项目数: ${projectCount}`);
|
||||
console.log(` 监管中项目: ${supervisionCount}`);
|
||||
console.log(` 已结项项目: ${completedCount}`);
|
||||
console.log('✅ 项目数据验证完成\n');
|
||||
|
||||
console.log('🎉 项目清单功能设置完成!');
|
||||
console.log('📝 接下来可以:');
|
||||
console.log(' 1. 启动后端服务器: npm start');
|
||||
console.log(' 2. 运行API测试: node test-projects-api.js');
|
||||
console.log(' 3. 在前端访问项目清单页面');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 设置项目清单功能失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果直接运行此脚本
|
||||
if (require.main === module) {
|
||||
setupProjects()
|
||||
.then(() => {
|
||||
console.log('✅ 脚本执行完成');
|
||||
process.exit(0);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('❌ 脚本执行失败:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = setupProjects;
|
||||
43
bank-backend/scripts/setup-supervision-tasks.js
Normal file
43
bank-backend/scripts/setup-supervision-tasks.js
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* 监管任务设置脚本
|
||||
* @file setup-supervision-tasks.js
|
||||
* @description 创建监管任务表并添加测试数据
|
||||
*/
|
||||
const { sequelize, SupervisionTask } = require('../models');
|
||||
const seedSupervisionTasks = require('./seed-supervision-tasks');
|
||||
|
||||
async function setupSupervisionTasks() {
|
||||
try {
|
||||
console.log('🚀 开始设置监管任务...');
|
||||
|
||||
// 测试数据库连接
|
||||
await sequelize.authenticate();
|
||||
console.log('✅ 数据库连接成功');
|
||||
|
||||
// 同步监管任务模型(创建表)
|
||||
await sequelize.sync({ force: false });
|
||||
console.log('✅ 数据库表同步完成');
|
||||
|
||||
// 添加测试数据
|
||||
await seedSupervisionTasks();
|
||||
|
||||
console.log('🎉 监管任务设置完成!');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 监管任务设置失败:', error);
|
||||
throw error;
|
||||
} finally {
|
||||
await sequelize.close();
|
||||
}
|
||||
}
|
||||
|
||||
// 运行设置
|
||||
setupSupervisionTasks()
|
||||
.then(() => {
|
||||
console.log('✅ 所有操作完成');
|
||||
process.exit(0);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('💥 操作失败:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -74,6 +74,8 @@ app.use('/api/transactions', require('./routes/transactions'));
|
||||
app.use('/api/dashboard', require('./routes/dashboard'));
|
||||
app.use('/api/loan-products', require('./routes/loanProducts'));
|
||||
app.use('/api/employees', require('./routes/employees'));
|
||||
app.use('/api/projects', require('./routes/projects'));
|
||||
app.use('/api/supervision-tasks', require('./routes/supervisionTasks'));
|
||||
// app.use('/api/reports', require('./routes/reports'));
|
||||
|
||||
// 根路径
|
||||
|
||||
96
bank-backend/test-create-project.js
Normal file
96
bank-backend/test-create-project.js
Normal file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* 测试创建项目接口
|
||||
*/
|
||||
const axios = require('axios');
|
||||
|
||||
const API_BASE_URL = 'http://localhost:5351';
|
||||
|
||||
async function testCreateProject() {
|
||||
try {
|
||||
console.log('🚀 开始测试创建项目接口...\n');
|
||||
|
||||
// 1. 先登录获取token
|
||||
console.log('1. 登录获取认证token...');
|
||||
const loginResponse = await axios.post(`${API_BASE_URL}/api/auth/login`, {
|
||||
username: 'admin',
|
||||
password: 'Admin123456'
|
||||
});
|
||||
|
||||
if (!loginResponse.data.success) {
|
||||
throw new Error('登录失败: ' + loginResponse.data.message);
|
||||
}
|
||||
|
||||
const token = loginResponse.data.data.token;
|
||||
console.log('✅ 登录成功,获取到token\n');
|
||||
|
||||
// 2. 测试创建项目
|
||||
console.log('2. 测试创建新项目...');
|
||||
const newProject = {
|
||||
name: '测试项目_' + new Date().getTime(),
|
||||
status: 'supervision',
|
||||
farmName: '测试养殖场',
|
||||
supervisionObject: '牛',
|
||||
supervisionQuantity: 100,
|
||||
supervisionPeriod: '12个月',
|
||||
supervisionAmount: 500000.00,
|
||||
startTime: '2024-01-01',
|
||||
endTime: '2024-12-31',
|
||||
earTag: 50,
|
||||
collar: 30,
|
||||
host: 20,
|
||||
loanOfficer: '张专员',
|
||||
description: '这是一个测试项目,用于验证创建接口功能'
|
||||
};
|
||||
|
||||
const createResponse = await axios.post(`${API_BASE_URL}/api/projects`, newProject, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
if (createResponse.data.success) {
|
||||
console.log('✅ 项目创建成功!');
|
||||
console.log('📋 创建的项目信息:');
|
||||
console.log(` - 项目ID: ${createResponse.data.data.id}`);
|
||||
console.log(` - 项目名称: ${createResponse.data.data.name}`);
|
||||
console.log(` - 养殖场: ${createResponse.data.data.farmName}`);
|
||||
console.log(` - 监管对象: ${createResponse.data.data.supervisionObject}`);
|
||||
console.log(` - 监管数量: ${createResponse.data.data.supervisionQuantity}`);
|
||||
console.log(` - 监管金额: ${createResponse.data.data.supervisionAmount}元`);
|
||||
console.log(` - 贷款专员: ${createResponse.data.data.loanOfficer}`);
|
||||
console.log(` - 创建时间: ${createResponse.data.data.createdAt}`);
|
||||
} else {
|
||||
console.log('❌ 项目创建失败:', createResponse.data.message);
|
||||
}
|
||||
|
||||
// 3. 验证项目是否在列表中
|
||||
console.log('\n3. 验证项目是否在列表中...');
|
||||
const listResponse = await axios.get(`${API_BASE_URL}/api/projects`, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
}
|
||||
});
|
||||
|
||||
if (listResponse.data.success) {
|
||||
const projects = listResponse.data.data.projects;
|
||||
const createdProject = projects.find(p => p.name === newProject.name);
|
||||
|
||||
if (createdProject) {
|
||||
console.log('✅ 项目已成功添加到列表中');
|
||||
console.log(`📊 当前总项目数: ${projects.length}`);
|
||||
} else {
|
||||
console.log('❌ 项目未在列表中找到');
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 测试失败:', error.message);
|
||||
if (error.response) {
|
||||
console.error('响应数据:', error.response.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 运行测试
|
||||
testCreateProject();
|
||||
34
bank-backend/test-project-direct.js
Normal file
34
bank-backend/test-project-direct.js
Normal file
@@ -0,0 +1,34 @@
|
||||
const { Project } = require('./models');
|
||||
|
||||
async function testProjectDirect() {
|
||||
try {
|
||||
console.log('🚀 直接测试项目模型...');
|
||||
|
||||
// 测试基本查询
|
||||
const count = await Project.count();
|
||||
console.log('✅ 项目总数:', count);
|
||||
|
||||
// 测试获取前5个项目
|
||||
const projects = await Project.findAll({
|
||||
limit: 5,
|
||||
order: [['createdAt', 'DESC']]
|
||||
});
|
||||
|
||||
console.log('✅ 获取项目成功,数量:', projects.length);
|
||||
|
||||
if (projects.length > 0) {
|
||||
console.log('第一个项目:', {
|
||||
id: projects[0].id,
|
||||
name: projects[0].name,
|
||||
status: projects[0].status,
|
||||
farmName: projects[0].farmName
|
||||
});
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 测试失败:', error.message);
|
||||
console.error('错误堆栈:', error.stack);
|
||||
}
|
||||
}
|
||||
|
||||
testProjectDirect();
|
||||
388
bank-backend/test-projects-api.js
Normal file
388
bank-backend/test-projects-api.js
Normal file
@@ -0,0 +1,388 @@
|
||||
const http = require('http');
|
||||
|
||||
// 测试配置
|
||||
const API_BASE_URL = 'http://localhost:5351';
|
||||
let authToken = '';
|
||||
|
||||
// 辅助函数:发送HTTP请求
|
||||
function makeRequest(options, data = null) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const req = http.request(options, (res) => {
|
||||
let responseData = '';
|
||||
|
||||
res.on('data', (chunk) => {
|
||||
responseData += chunk;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
try {
|
||||
const result = {
|
||||
statusCode: res.statusCode,
|
||||
headers: res.headers,
|
||||
data: responseData ? JSON.parse(responseData) : null
|
||||
};
|
||||
resolve(result);
|
||||
} catch (error) {
|
||||
reject(new Error(`解析响应失败: ${error.message}`));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', (error) => {
|
||||
reject(error);
|
||||
});
|
||||
|
||||
if (data) {
|
||||
req.write(JSON.stringify(data));
|
||||
}
|
||||
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
// 登录获取认证令牌
|
||||
async function login() {
|
||||
console.log('🔐 正在登录...');
|
||||
|
||||
const options = {
|
||||
hostname: 'localhost',
|
||||
port: 5351,
|
||||
path: '/api/auth/login',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
};
|
||||
|
||||
const loginData = {
|
||||
username: 'admin',
|
||||
password: 'Admin123456'
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await makeRequest(options, loginData);
|
||||
|
||||
if (response.statusCode === 200 && response.data.success) {
|
||||
authToken = response.data.data.token;
|
||||
console.log('✅ 登录成功');
|
||||
return true;
|
||||
} else {
|
||||
console.error('❌ 登录失败:', response.data.message);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ 登录请求失败:', error.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 测试获取项目列表
|
||||
async function testGetProjects() {
|
||||
console.log('\n📋 测试获取项目列表...');
|
||||
|
||||
const options = {
|
||||
hostname: 'localhost',
|
||||
port: 5351,
|
||||
path: '/api/projects',
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${authToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await makeRequest(options);
|
||||
|
||||
if (response.statusCode === 200 && response.data.success) {
|
||||
console.log('✅ 获取项目列表成功');
|
||||
console.log(` 项目数量: ${response.data.data.projects.length}`);
|
||||
console.log(` 总数量: ${response.data.data.pagination.total}`);
|
||||
|
||||
// 显示前3个项目的基本信息
|
||||
const projects = response.data.data.projects.slice(0, 3);
|
||||
projects.forEach((project, index) => {
|
||||
console.log(` 项目${index + 1}: ${project.name} (${project.status}) - ${project.farmName}`);
|
||||
});
|
||||
|
||||
return true;
|
||||
} else {
|
||||
console.error('❌ 获取项目列表失败:', response.data.message);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ 获取项目列表请求失败:', error.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 测试获取项目统计
|
||||
async function testGetProjectStats() {
|
||||
console.log('\n📊 测试获取项目统计...');
|
||||
|
||||
const options = {
|
||||
hostname: 'localhost',
|
||||
port: 5351,
|
||||
path: '/api/projects/stats',
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${authToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await makeRequest(options);
|
||||
|
||||
if (response.statusCode === 200 && response.data.success) {
|
||||
console.log('✅ 获取项目统计成功');
|
||||
const stats = response.data.data;
|
||||
console.log(` 总项目数: ${stats.total}`);
|
||||
console.log(` 监管中: ${stats.supervision}`);
|
||||
console.log(` 已结项: ${stats.completed}`);
|
||||
console.log(` 总监管金额: ${stats.totalAmount?.toFixed(2) || 0} 元`);
|
||||
console.log(` 总监管数量: ${stats.totalQuantity || 0} 头`);
|
||||
return true;
|
||||
} else {
|
||||
console.error('❌ 获取项目统计失败:', response.data.message);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ 获取项目统计请求失败:', error.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 测试创建项目
|
||||
async function testCreateProject() {
|
||||
console.log('\n➕ 测试创建项目...');
|
||||
|
||||
const options = {
|
||||
hostname: 'localhost',
|
||||
port: 5351,
|
||||
path: '/api/projects',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${authToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
};
|
||||
|
||||
const projectData = {
|
||||
name: '测试项目',
|
||||
status: 'supervision',
|
||||
farmName: '测试养殖场',
|
||||
supervisionObject: '牛',
|
||||
supervisionQuantity: 20,
|
||||
supervisionPeriod: '30天',
|
||||
supervisionAmount: 50000.00,
|
||||
startTime: '2024-01-01',
|
||||
endTime: '2024-12-31',
|
||||
earTag: 10,
|
||||
collar: 10,
|
||||
host: 1,
|
||||
loanOfficer: '测试专员',
|
||||
description: '这是一个测试项目'
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await makeRequest(options, projectData);
|
||||
|
||||
if (response.statusCode === 201 && response.data.success) {
|
||||
console.log('✅ 创建项目成功');
|
||||
console.log(` 项目ID: ${response.data.data.id}`);
|
||||
console.log(` 项目名称: ${response.data.data.name}`);
|
||||
return response.data.data.id;
|
||||
} else {
|
||||
console.error('❌ 创建项目失败:', response.data.message);
|
||||
return null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ 创建项目请求失败:', error.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 测试获取项目详情
|
||||
async function testGetProjectById(projectId) {
|
||||
console.log('\n🔍 测试获取项目详情...');
|
||||
|
||||
const options = {
|
||||
hostname: 'localhost',
|
||||
port: 5351,
|
||||
path: `/api/projects/${projectId}`,
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${authToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await makeRequest(options);
|
||||
|
||||
if (response.statusCode === 200 && response.data.success) {
|
||||
console.log('✅ 获取项目详情成功');
|
||||
const project = response.data.data;
|
||||
console.log(` 项目名称: ${project.name}`);
|
||||
console.log(` 养殖场: ${project.farmName}`);
|
||||
console.log(` 监管对象: ${project.supervisionObject}`);
|
||||
console.log(` 监管数量: ${project.supervisionQuantity}`);
|
||||
console.log(` 监管金额: ${project.supervisionAmount} 元`);
|
||||
return true;
|
||||
} else {
|
||||
console.error('❌ 获取项目详情失败:', response.data.message);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ 获取项目详情请求失败:', error.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 测试更新项目
|
||||
async function testUpdateProject(projectId) {
|
||||
console.log('\n✏️ 测试更新项目...');
|
||||
|
||||
const options = {
|
||||
hostname: 'localhost',
|
||||
port: 5351,
|
||||
path: `/api/projects/${projectId}`,
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${authToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
};
|
||||
|
||||
const updateData = {
|
||||
supervisionQuantity: 25,
|
||||
supervisionAmount: 60000.00,
|
||||
description: '更新后的项目描述'
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await makeRequest(options, updateData);
|
||||
|
||||
if (response.statusCode === 200 && response.data.success) {
|
||||
console.log('✅ 更新项目成功');
|
||||
const project = response.data.data;
|
||||
console.log(` 更新后监管数量: ${project.supervisionQuantity}`);
|
||||
console.log(` 更新后监管金额: ${project.supervisionAmount} 元`);
|
||||
return true;
|
||||
} else {
|
||||
console.error('❌ 更新项目失败:', response.data.message);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ 更新项目请求失败:', error.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 测试删除项目
|
||||
async function testDeleteProject(projectId) {
|
||||
console.log('\n🗑️ 测试删除项目...');
|
||||
|
||||
const options = {
|
||||
hostname: 'localhost',
|
||||
port: 5351,
|
||||
path: `/api/projects/${projectId}`,
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${authToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await makeRequest(options);
|
||||
|
||||
if (response.statusCode === 200 && response.data.success) {
|
||||
console.log('✅ 删除项目成功');
|
||||
return true;
|
||||
} else {
|
||||
console.error('❌ 删除项目失败:', response.data.message);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ 删除项目请求失败:', error.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 测试搜索项目
|
||||
async function testSearchProjects() {
|
||||
console.log('\n🔍 测试搜索项目...');
|
||||
|
||||
const options = {
|
||||
hostname: 'localhost',
|
||||
port: 5351,
|
||||
path: '/api/projects?search=张洪彬&status=completed',
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${authToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await makeRequest(options);
|
||||
|
||||
if (response.statusCode === 200 && response.data.success) {
|
||||
console.log('✅ 搜索项目成功');
|
||||
console.log(` 搜索结果数量: ${response.data.data.projects.length}`);
|
||||
const projects = response.data.data.projects;
|
||||
projects.forEach((project, index) => {
|
||||
console.log(` 结果${index + 1}: ${project.name} - ${project.farmName}`);
|
||||
});
|
||||
return true;
|
||||
} else {
|
||||
console.error('❌ 搜索项目失败:', response.data.message);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ 搜索项目请求失败:', error.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 主测试函数
|
||||
async function runTests() {
|
||||
console.log('🚀 开始测试项目清单API接口...\n');
|
||||
|
||||
// 1. 登录
|
||||
const loginSuccess = await login();
|
||||
if (!loginSuccess) {
|
||||
console.log('❌ 登录失败,无法继续测试');
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 测试获取项目列表
|
||||
await testGetProjects();
|
||||
|
||||
// 3. 测试获取项目统计
|
||||
await testGetProjectStats();
|
||||
|
||||
// 4. 测试搜索项目
|
||||
await testSearchProjects();
|
||||
|
||||
// 5. 测试创建项目
|
||||
const projectId = await testCreateProject();
|
||||
|
||||
if (projectId) {
|
||||
// 6. 测试获取项目详情
|
||||
await testGetProjectById(projectId);
|
||||
|
||||
// 7. 测试更新项目
|
||||
await testUpdateProject(projectId);
|
||||
|
||||
// 8. 测试删除项目
|
||||
await testDeleteProject(projectId);
|
||||
}
|
||||
|
||||
console.log('\n🎉 项目清单API接口测试完成!');
|
||||
}
|
||||
|
||||
// 运行测试
|
||||
runTests().catch(console.error);
|
||||
58
bank-backend/test-projects-simple.js
Normal file
58
bank-backend/test-projects-simple.js
Normal file
@@ -0,0 +1,58 @@
|
||||
const http = require('http');
|
||||
|
||||
// 测试项目接口
|
||||
function testProjectsAPI() {
|
||||
const options = {
|
||||
hostname: 'localhost',
|
||||
port: 5351,
|
||||
path: '/api/projects?page=1&limit=12&search=&status=',
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
};
|
||||
|
||||
const req = http.request(options, (res) => {
|
||||
let data = '';
|
||||
|
||||
res.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
console.log('状态码:', res.statusCode);
|
||||
console.log('响应头:', res.headers);
|
||||
console.log('响应体:', data);
|
||||
|
||||
if (res.statusCode === 500) {
|
||||
console.log('\n❌ 服务器内部错误');
|
||||
try {
|
||||
const errorData = JSON.parse(data);
|
||||
console.log('错误信息:', errorData.message);
|
||||
if (errorData.error) {
|
||||
console.log('详细错误:', errorData.error);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('无法解析错误响应');
|
||||
}
|
||||
} else if (res.statusCode === 200) {
|
||||
console.log('\n✅ 请求成功');
|
||||
try {
|
||||
const responseData = JSON.parse(data);
|
||||
console.log('项目数量:', responseData.data?.projects?.length || 0);
|
||||
} catch (e) {
|
||||
console.log('无法解析成功响应');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', (error) => {
|
||||
console.error('请求错误:', error.message);
|
||||
});
|
||||
|
||||
req.end();
|
||||
}
|
||||
|
||||
console.log('🚀 测试项目接口...');
|
||||
testProjectsAPI();
|
||||
172
bank-backend/test-supervision-tasks-api.js
Normal file
172
bank-backend/test-supervision-tasks-api.js
Normal file
@@ -0,0 +1,172 @@
|
||||
/**
|
||||
* 监管任务API测试脚本
|
||||
* @file test-supervision-tasks-api.js
|
||||
* @description 测试监管任务相关的API接口
|
||||
*/
|
||||
const axios = require('axios');
|
||||
|
||||
const API_BASE_URL = 'http://localhost:5351';
|
||||
|
||||
async function testSupervisionTasksAPI() {
|
||||
try {
|
||||
console.log('🚀 开始测试监管任务API...\n');
|
||||
|
||||
// 1. 先登录获取token
|
||||
console.log('1. 登录获取认证token...');
|
||||
const loginResponse = await axios.post(`${API_BASE_URL}/api/auth/login`, {
|
||||
username: 'admin',
|
||||
password: 'Admin123456'
|
||||
});
|
||||
|
||||
if (!loginResponse.data.success) {
|
||||
throw new Error('登录失败: ' + loginResponse.data.message);
|
||||
}
|
||||
|
||||
const token = loginResponse.data.data.token;
|
||||
console.log('✅ 登录成功,获取到token\n');
|
||||
|
||||
const headers = {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
};
|
||||
|
||||
// 2. 测试获取监管任务列表
|
||||
console.log('2. 测试获取监管任务列表...');
|
||||
const listResponse = await axios.get(`${API_BASE_URL}/api/supervision-tasks`, { headers });
|
||||
|
||||
if (listResponse.data.success) {
|
||||
console.log('✅ 获取监管任务列表成功');
|
||||
console.log(`📊 共 ${listResponse.data.data.tasks.length} 个监管任务`);
|
||||
console.log(`📈 分页信息: 第${listResponse.data.data.pagination.currentPage}页,共${listResponse.data.data.pagination.totalPages}页\n`);
|
||||
} else {
|
||||
console.log('❌ 获取监管任务列表失败:', listResponse.data.message);
|
||||
}
|
||||
|
||||
// 3. 测试获取监管任务统计
|
||||
console.log('3. 测试获取监管任务统计...');
|
||||
const statsResponse = await axios.get(`${API_BASE_URL}/api/supervision-tasks/stats`, { headers });
|
||||
|
||||
if (statsResponse.data.success) {
|
||||
console.log('✅ 获取监管任务统计成功');
|
||||
console.log('📊 统计信息:');
|
||||
console.log(` 总计: ${statsResponse.data.data.total}`);
|
||||
console.log(` 待监管: ${statsResponse.data.data.pending}`);
|
||||
console.log(` 监管中: ${statsResponse.data.data.supervising}`);
|
||||
console.log(` 已完成: ${statsResponse.data.data.completed}`);
|
||||
console.log(` 已暂停: ${statsResponse.data.data.suspended}\n`);
|
||||
} else {
|
||||
console.log('❌ 获取监管任务统计失败:', statsResponse.data.message);
|
||||
}
|
||||
|
||||
// 4. 测试创建监管任务
|
||||
console.log('4. 测试创建监管任务...');
|
||||
const newTask = {
|
||||
applicationNumber: 'APP_TEST_' + Date.now(),
|
||||
contractNumber: 'CONTRACT_TEST_' + Date.now(),
|
||||
productName: '测试农业贷款产品',
|
||||
customerName: '测试客户',
|
||||
idType: 'id_card',
|
||||
idNumber: '110101199001011234',
|
||||
assetType: 'cattle',
|
||||
assetQuantity: 10,
|
||||
supervisionStatus: 'pending',
|
||||
startTime: '2024-12-20',
|
||||
endTime: '2024-12-31',
|
||||
loanAmount: 100000.00,
|
||||
interestRate: 0.0600,
|
||||
loanTerm: 12,
|
||||
supervisorName: '测试监管员',
|
||||
supervisorPhone: '13800138000',
|
||||
farmAddress: '测试养殖场地址',
|
||||
remarks: '这是一个测试监管任务'
|
||||
};
|
||||
|
||||
const createResponse = await axios.post(`${API_BASE_URL}/api/supervision-tasks`, newTask, { headers });
|
||||
|
||||
if (createResponse.data.success) {
|
||||
console.log('✅ 创建监管任务成功');
|
||||
console.log(`📋 任务ID: ${createResponse.data.data.id}`);
|
||||
console.log(`📋 申请单号: ${createResponse.data.data.applicationNumber}\n`);
|
||||
|
||||
const taskId = createResponse.data.data.id;
|
||||
|
||||
// 5. 测试获取监管任务详情
|
||||
console.log('5. 测试获取监管任务详情...');
|
||||
const detailResponse = await axios.get(`${API_BASE_URL}/api/supervision-tasks/${taskId}`, { headers });
|
||||
|
||||
if (detailResponse.data.success) {
|
||||
console.log('✅ 获取监管任务详情成功');
|
||||
console.log(`📋 客户姓名: ${detailResponse.data.data.customerName}`);
|
||||
console.log(`📋 监管状态: ${detailResponse.data.data.supervisionStatus}\n`);
|
||||
} else {
|
||||
console.log('❌ 获取监管任务详情失败:', detailResponse.data.message);
|
||||
}
|
||||
|
||||
// 6. 测试更新监管任务
|
||||
console.log('6. 测试更新监管任务...');
|
||||
const updateData = {
|
||||
supervisionStatus: 'supervising',
|
||||
remarks: '更新后的备注信息'
|
||||
};
|
||||
|
||||
const updateResponse = await axios.put(`${API_BASE_URL}/api/supervision-tasks/${taskId}`, updateData, { headers });
|
||||
|
||||
if (updateResponse.data.success) {
|
||||
console.log('✅ 更新监管任务成功');
|
||||
console.log(`📋 新状态: ${updateResponse.data.data.supervisionStatus}\n`);
|
||||
} else {
|
||||
console.log('❌ 更新监管任务失败:', updateResponse.data.message);
|
||||
}
|
||||
|
||||
// 7. 测试批量更新状态
|
||||
console.log('7. 测试批量更新状态...');
|
||||
const batchUpdateData = {
|
||||
ids: [taskId],
|
||||
supervisionStatus: 'completed'
|
||||
};
|
||||
|
||||
const batchUpdateResponse = await axios.put(`${API_BASE_URL}/api/supervision-tasks/batch/status`, batchUpdateData, { headers });
|
||||
|
||||
if (batchUpdateResponse.data.success) {
|
||||
console.log('✅ 批量更新状态成功');
|
||||
console.log(`📋 更新数量: ${batchUpdateResponse.data.data.updatedCount}\n`);
|
||||
} else {
|
||||
console.log('❌ 批量更新状态失败:', batchUpdateResponse.data.message);
|
||||
}
|
||||
|
||||
// 8. 测试删除监管任务
|
||||
console.log('8. 测试删除监管任务...');
|
||||
const deleteResponse = await axios.delete(`${API_BASE_URL}/api/supervision-tasks/${taskId}`, { headers });
|
||||
|
||||
if (deleteResponse.data.success) {
|
||||
console.log('✅ 删除监管任务成功\n');
|
||||
} else {
|
||||
console.log('❌ 删除监管任务失败:', deleteResponse.data.message);
|
||||
}
|
||||
} else {
|
||||
console.log('❌ 创建监管任务失败:', createResponse.data.message);
|
||||
}
|
||||
|
||||
// 9. 测试搜索功能
|
||||
console.log('9. 测试搜索功能...');
|
||||
const searchResponse = await axios.get(`${API_BASE_URL}/api/supervision-tasks?search=张三&supervisionStatus=supervising`, { headers });
|
||||
|
||||
if (searchResponse.data.success) {
|
||||
console.log('✅ 搜索功能测试成功');
|
||||
console.log(`📊 搜索结果: ${searchResponse.data.data.tasks.length} 条记录\n`);
|
||||
} else {
|
||||
console.log('❌ 搜索功能测试失败:', searchResponse.data.message);
|
||||
}
|
||||
|
||||
console.log('🎉 所有API测试完成!');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 测试失败:', error.message);
|
||||
if (error.response) {
|
||||
console.error('响应数据:', error.response.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 运行测试
|
||||
testSupervisionTasksAPI();
|
||||
55
bank-backend/test-supervision-tasks-simple.js
Normal file
55
bank-backend/test-supervision-tasks-simple.js
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* 简单监管任务API测试
|
||||
*/
|
||||
const axios = require('axios');
|
||||
|
||||
const API_BASE_URL = 'http://localhost:5351';
|
||||
|
||||
async function testSupervisionTasksSimple() {
|
||||
try {
|
||||
console.log('🚀 开始简单测试监管任务API...\n');
|
||||
|
||||
// 1. 测试登录
|
||||
console.log('1. 测试登录...');
|
||||
const loginResponse = await axios.post(`${API_BASE_URL}/api/auth/login`, {
|
||||
username: 'admin',
|
||||
password: 'Admin123456'
|
||||
});
|
||||
|
||||
console.log('登录响应:', loginResponse.data);
|
||||
|
||||
if (!loginResponse.data.success) {
|
||||
throw new Error('登录失败: ' + loginResponse.data.message);
|
||||
}
|
||||
|
||||
const token = loginResponse.data.data.token;
|
||||
console.log('✅ 登录成功\n');
|
||||
|
||||
// 2. 测试获取监管任务列表
|
||||
console.log('2. 测试获取监管任务列表...');
|
||||
const listResponse = await axios.get(`${API_BASE_URL}/api/supervision-tasks`, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
console.log('列表响应:', listResponse.data);
|
||||
|
||||
if (listResponse.data.success) {
|
||||
console.log('✅ 获取监管任务列表成功');
|
||||
console.log(`📊 共 ${listResponse.data.data.tasks.length} 个监管任务`);
|
||||
} else {
|
||||
console.log('❌ 获取监管任务列表失败:', listResponse.data.message);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 测试失败:', error.message);
|
||||
if (error.response) {
|
||||
console.error('响应状态:', error.response.status);
|
||||
console.error('响应数据:', error.response.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
testSupervisionTasksSimple();
|
||||
Reference in New Issue
Block a user