修复数据库迁移乱码并统一 MySQL 8 配置

This commit is contained in:
wkc
2026-03-28 10:09:34 +08:00
parent bc7011313f
commit 040a03cd36
77 changed files with 1682 additions and 6026 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

3
.gitignore vendored
View File

@@ -45,3 +45,6 @@ nbdist/
!*/build/*.java
!*/build/*.html
!*/build/*.xml
logs/

View File

@@ -1,135 +0,0 @@
# 修复MySQL数据库注释乱码
## 问题描述
MySQL数据库表和字段的中文注释显示为乱码在Navicat等数据库管理工具中查看时出现 `??` 或其他乱码字符。
## 诊断方法
```bash
# 检查字段注释的十六进制编码
mysql -h <host> -P <port> -u <user> -p<password> "<database>" -e "
SELECT COLUMN_NAME, HEX(COLUMN_COMMENT) as comment_hex
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA='<database>' AND TABLE_NAME='<table_name>';
"
```
**判断标准:**
- ✅ 正确的UTF-8中文`E4`-`E9` 开头(如 `E698AF` = `是`
- ❌ 错误编码:以 `C3` 开头(表示双重编码问题)
## 解决方案
### 方法1创建UTF-8编码的SQL文件推荐
1. **创建SQL文件**确保保存为UTF-8编码
```sql
-- fix_comments.sql
USE `<database>`;
SET NAMES utf8mb4;
ALTER TABLE `<table_name>` COMMENT = '正确的中文注释';
ALTER TABLE `<table_name>`
MODIFY COLUMN `column1` varchar(50) DEFAULT NULL COMMENT '字段1中文注释',
MODIFY COLUMN `column2` varchar(50) DEFAULT NULL COMMENT '字段2中文注释',
-- ... 更多字段
```
2. **使用utf8mb4字符集执行**
```bash
mysql -h <host> -P <port> -u <user> -p<password> \
--default-character-set=utf8mb4 "<database>" < fix_comments.sql
```
### 方法2验证SQL文件编码
```bash
# 检查文件是否为UTF-8编码
file fix_comments.sql
# 应该输出: Unicode text, UTF-8 text
```
### 方法3通过heredoc创建SQL文件跨平台
```bash
cat > fix_comments.sql << 'SQLEOF'
USE `your_database`;
SET NAMES utf8mb4;
ALTER TABLE your_table MODIFY COLUMN your_column varchar(10) DEFAULT NULL COMMENT '正确的中文注释';
SQLEOF
```
## 验证修复结果
```bash
# 查看表注释
mysql -h <host> -u <user> -p<password> "<database>" -e "
SELECT table_name, HEX(table_comment) as comment_hex
FROM information_schema.tables
WHERE table_schema='<database>' AND table_name='<table_name>';
"
# 查看字段注释
mysql -h <host> -u <user> -p<password> "<database>" -e "
SELECT COLUMN_NAME, COLUMN_COMMENT
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA='<database>' AND TABLE_NAME='<table_name>'
ORDER BY ORDINAL_POSITION;
"
# 检查是否还有乱码字段C3开头
mysql -h <host> -u <user> -p<password> "<database>" -e "
SELECT COUNT(*) as bad_comments
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA='<database>' AND TABLE_NAME='<table_name>'
AND HEX(COLUMN_COMMENT) REGEXP '^C3';
"
```
## 常见错误及原因
| 错误现象 | 原因 | 解决方案 |
|----------------------|----------------------------|-----------------------|
| `C3A6CB9C...` (C3开头) | 双重编码UTF-8被当作GBK处理后再转UTF-8 | 使用UTF-8文件 + utf8mb4执行 |
| Windows命令行显示乱码 | 终端编码问题,数据库实际正确 | 用HEX()验证实际存储 |
| SQL文件执行后仍乱码 | 文件未保存为UTF-8 | 用`file`命令检查编码 |
## 最佳实践
1. **所有SQL文件使用UTF-8编码保存**
2. **始终使用 `--default-character-set=utf8mb4` 参数**
3. **在SQL开头添加 `SET NAMES utf8mb4;`**
4. **用HEX()验证而非肉眼判断**
5. **批量修复时用脚本生成SQL文件**
## 示例批量生成修复SQL
```bash
#!/bin/bash
# 为指定表生成修复SQL
DB_NAME="your_database"
TABLE_NAME="your_table"
cat > fix_${TABLE_NAME}_comments.sql << SQLEOF
USE \`${DB_NAME}\`;
SET NAMES utf8mb4;
ALTER TABLE \`${TABLE_NAME}\`
COMMENT = '表的中文名称';
ALTER TABLE \`${TABLE_NAME}\`
MODIFY COLUMN \`id\` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
MODIFY COLUMN \`name\` varchar(100) DEFAULT NULL COMMENT '名称',
-- 添加更多字段...
SQLEOF
# 执行修复
mysql -h localhost -u root -p${DB_PASS} \
--default-character-set=utf8mb4 "${DB_NAME}" < fix_${TABLE_NAME}_comments.sql
```

View File

@@ -1,166 +0,0 @@
# 利率定价流程 API 测试报告
## 测试概述
**测试时间**: 2025-01-20 10:34:00
**测试环境**: http://localhost:8080
**测试账号**: admin / admin123
**测试工具**: 自动化测试脚本 (run-api-tests.sh)
## 测试结果汇总
| 指标 | 数值 |
|------|------|
| 总测试数 | 13 |
| 通过 | 3 |
| 失败 | 10 |
| 通过率 | 23% |
---
## 详细测试结果
### ✅ 通过的测试用例 (3个)
| 序号 | 测试用例 | 说明 |
|------|----------|------|
| 11 | 异常测试-客户内码为空 | 正确返回验证错误 |
| 12 | 异常测试-贷款利率为空 | 正确返回验证错误 |
| 13 | 异常测试-查询不存在的流程 | 正确返回记录不存在 |
### ❌ 失败的测试用例 (10个)
| 序号 | 测试用例 | 失败原因 |
|------|----------|----------|
| 1 | 发起流程-个人客户信用贷款 | 数据库表不存在 |
| 2 | 发起流程-企业客户抵押贷款 | 数据库表不存在 |
| 3 | 发起流程-农业担保贷款 | 数据库表不存在 |
| 4 | 发起流程-个人客户质押贷款 | 数据库表不存在 |
| 5 | 查询流程列表-默认分页 | 数据库表不存在 |
| 6 | 查询流程列表-筛选个人客户 | URL编码问题 |
| 7 | 查询流程列表-筛选企业客户 | URL编码问题 |
| 8 | 查询流程列表-搜索张三 | URL编码问题 |
| 9 | 查询流程列表-筛选信用贷款 | URL编码问题 (中文参数) |
| 10 | 查询流程详情-CUST20250119001 | 数据库表不存在 |
---
## 问题分析
### 🔴 严重问题
#### 1. 数据库表不存在
**问题描述**: 表 `loan_pricing_workflow` 在数据库 `ruoyi-test` 中不存在
**影响范围**: 所有涉及数据库操作的接口
**解决方案**:
执行 SQL 脚本创建表:
```sql
-- 文件位置: sql/loan_pricing_workflow.sql
-- 需要在数据库 ruoyi-test 中执行此脚本
```
**执行命令** (需要数据库访问权限):
```bash
mysql -h 116.62.17.81 -P 40627 -u root -p ruoyi-test < sql/loan_pricing_workflow.sql
```
### 🟡 中等问题
#### 2. URL编码问题
**问题描述**: 中文参数在 URL 中未正确编码
**影响范围**:
- 查询流程列表时的筛选功能 (客户类型、担保方式等)
**解决方案**:
在测试脚本中对中文参数进行 URL 编码
---
## API 接口清单
| 接口 | 方法 | 路径 | 状态 |
|------|------|------|------|
| 发起利率定价流程 | POST | `/loanPricing/workflow/create` | ⚠️ 待数据库表创建后测试 |
| 查询流程列表 | GET | `/loanPricing/workflow/list` | ⚠️ 待数据库表创建后测试 |
| 查询流程详情 | GET | `/loanPricing/workflow/{serialNum}` | ⚠️ 待数据库表创建后测试 |
---
## 功能验证
### 参数验证 ✅
- 必填字段验证正常工作
- 客户内码 (custIsn) 不能为空
- 贷款利率 (loanRate) 不能为空
- 客户类型 (custType) 不能为空
- 担保方式 (guarType) 不能为空
### 异常处理 ✅
- 查询不存在的记录时正确返回错误提示
- 参数验证失败时返回明确的错误信息
---
## 后续步骤
### 优先级 P0 (必须完成)
1. **创建数据库表**
- 执行 `sql/loan_pricing_workflow.sql` 脚本
- 验证表创建成功
2. **重新执行测试**
- 运行 `bash run-api-tests.sh`
- 确认所有功能测试通过
### 优先级 P1 (建议完成)
1. **修复 URL 编码问题**
- 更新测试脚本处理中文参数
- 或使用 POST + JSON body 进行查询
2. **补充测试用例**
- 添加更多边界条件测试
- 添加并发测试
- 添加性能测试
---
## 附录
### 测试数据样本
**个人客户信用贷款**:
```json
{
"custIsn": "CUST20250119001",
"custType": "个人",
"guarType": "信用",
"applyAmt": "50000",
"loanRate": "4.35",
"custName": "张三"
}
```
**企业客户抵押贷款**:
```json
{
"custIsn": "CUST20250119002",
"custType": "企业",
"guarType": "抵押",
"applyAmt": "500000",
"loanRate": "3.85",
"custName": "测试科技有限公司"
}
```
### 相关文件
- 测试脚本: `run-api-tests.sh`
- SQL 脚本: `sql/loan_pricing_workflow.sql`
- Controller: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/controller/LoanPricingWorkflowController.java`
---
**报告生成时间**: 2025-01-20 10:34:00
**测试执行者**: Claude Code AI Assistant

View File

@@ -1,32 +0,0 @@
利率定价流程 API 测试报告
====================================
测试时间: 2026-01-20 10:34:00
测试环境: http://localhost:8080
测试账号: admin
测试统计
--------
总测试数: 13
通过数: 3
失败数: 10
通过率: 23%
测试用例详情
--------
✗ 发起流程-个人客户信用贷款 - 期望码: 200, 实际: 500
✗ 发起流程-企业客户抵押贷款 - 期望码: 200, 实际: 500
✗ 发起流程-农业担保贷款 - 期望码: 200, 实际: 500
✗ 发起流程-个人客户质押贷款 - 期望码: 200, 实际: 500
✗ 查询流程列表-默认分页 - 期望码: 200, 实际: 500
✗ 查询流程列表-筛选个人客户 - 期望码: 200, 实际:
✗ 查询流程列表-筛选企业客户 - 期望码: 200, 实际:
✗ 查询流程列表-搜索张三 - 期望码: 200, 实际:
✗ 查询流程列表-筛选信用贷款 - 期望码: 200, 实际:
✗ 查询流程详情-CUST20250119001 - 期望码: 200, 实际: 500
✓ 异常测试-客户内码为空
✓ 异常测试-贷款利率为空
✓ 异常测试-查询不存在的流程
====================================
测试结束

View File

@@ -1,32 +0,0 @@
利率定价流程 API 测试报告
====================================
测试时间: 2026-01-20 10:36:59
测试环境: http://localhost:8080
测试账号: admin
测试统计
--------
总测试数: 13
通过数: 8
失败数: 5
通过率: 61%
测试用例详情
--------
✓ 发起流程-个人客户信用贷款
✓ 发起流程-企业客户抵押贷款
✓ 发起流程-农业担保贷款
✓ 发起流程-个人客户质押贷款
✓ 查询流程列表-默认分页
✗ 查询流程列表-筛选个人客户 - 期望码: 200, 实际:
✗ 查询流程列表-筛选企业客户 - 期望码: 200, 实际:
✗ 查询流程列表-搜索张三 - 期望码: 200, 实际:
✗ 查询流程列表-筛选信用贷款 - 期望码: 200, 实际:
✗ 查询流程详情-CUST20250119001 - 期望码: 200, 实际: 500
✓ 异常测试-客户内码为空
✓ 异常测试-贷款利率为空
✓ 异常测试-查询不存在的流程
====================================
测试结束

View File

@@ -1,306 +0,0 @@
# 利率定价流程 API 测试报告
## 测试概述
| 项目 | 内容 |
|------|------|
| **测试时间** | 2025-01-20 10:36:58 |
| **测试环境** | http://localhost:8080 |
| **测试账号** | admin / admin123 |
| **数据库** | ruoyi-test (远程) |
| **测试工具** | 自动化测试脚本 + curl |
---
## 测试结果汇总
| 指标 | 数值 |
|------|------|
| **总测试数** | 13 |
| **通过** | 8 |
| **失败** | 5 |
| **通过率** | **61.5%** |
| **核心功能通过率** | **100%** ✅ |
> **说明**: 失败的 5 个测试用例均为 URL 编码问题(中文参数),这是测试脚本的问题,不影响 API 本身的功能。核心 API 功能全部通过测试。
---
## 功能测试结果
### ✅ 通过的测试 (8个)
| 序号 | 测试用例 | 结果 |
|------|----------|------|
| 1 | 发起流程-个人客户信用贷款 | ✅ 通过 - 流水号: 20260120103654993 |
| 2 | 发起流程-企业客户抵押贷款 | ✅ 通过 - 流水号: 20260120103655435 |
| 3 | 发起流程-农业担保贷款 | ✅ 通过 - 流水号: 20260120103655839 |
| 4 | 发起流程-个人客户质押贷款 | ✅ 通过 - 流水号: 20260120103656259 |
| 5 | 查询流程列表-默认分页 | ✅ 通过 - 返回 4 条记录 |
| 11 | 异常测试-客户内码为空 | ✅ 通过 - 参数验证正常 |
| 12 | 异常测试-贷款利率为空 | ✅ 通过 - 参数验证正常 |
| 13 | 异常测试-查询不存在的流程 | ✅ 通过 - 正确返回"记录不存在" |
### ⚠️ URL编码问题 (5个)
| 序号 | 测试用例 | 问题 |
|------|----------|------|
| 6 | 查询流程列表-筛选个人客户 | curl 未对中文参数进行 URL 编码 |
| 7 | 查询流程列表-筛选企业客户 | curl 未对中文参数进行 URL 编码 |
| 8 | 查询流程列表-搜索张三 | curl 未对中文参数进行 URL 编码 |
| 9 | 查询流程列表-筛选信用贷款 | curl 未对中文参数进行 URL 编码 |
| 10 | 查询流程详情-CUST20250119001 | ✅ 实际测试通过 - 使用正确流水号查询成功 |
---
## API 接口验证
### 1. POST /loanPricing/workflow/create - 发起利率定价流程
**功能**: ✅ 正常工作
**测试数据**:
```json
{
"custIsn": "CUST20250119001",
"custType": "个人",
"guarType": "信用",
"applyAmt": "50000",
"loanRate": "4.35",
"custName": "张三"
}
```
**返回结果**:
- 自动生成业务流水号 (格式: 时间戳 + 毫秒)
- 自动记录创建者 (admin)
- 自动记录创建时间和更新时间
**创建的记录**:
| 流水号 | 客户 | 类型 | 担保方式 | 金额 | 利率 |
|--------|------|------|----------|------|------|
| 20260120103654993 | 张三 | 个人 | 信用 | 50000 | 4.35% |
| 20260120103655435 | 测试科技有限公司 | 企业 | 抵押 | 500000 | 3.85% |
| 20260120103655839 | 绿源农业合作社 | 企业 | 保证 | 300000 | 4.15% |
| 20260120103656259 | 李四 | 个人 | 质押 | 100000 | 4.25% |
---
### 2. GET /loanPricing/workflow/list - 查询流程列表
**功能**: ✅ 正常工作
**请求参数**:
- `pageNum`: 页码 (默认 1)
- `pageSize`: 每页大小 (默认 10)
- 支持按以下字段筛选:
- `custType` - 客户类型
- `guarType` - 担保方式
- `custName` - 客户名称
- `orgCode` - 机构编码
- `createBy` - 创建者
**响应示例**:
```json
{
"total": 4,
"rows": [...],
"code": 200,
"msg": "查询成功"
}
```
---
### 3. GET /loanPricing/workflow/{serialNum} - 查询流程详情
**功能**: ✅ 正常工作
**测试用例**: `GET /loanPricing/workflow/20260120103654993`
**响应示例**:
```json
{
"msg": "操作成功",
"code": 200,
"data": {
"id": 1,
"serialNum": "20260120103654993",
"custIsn": "CUST20250119001",
"custName": "张三",
"applyAmt": "50000",
"loanRate": "4.35",
...
}
}
```
**异常处理**:
- 查询不存在的记录时正确返回: `{"msg":"记录不存在","code":500}`
---
## 参数验证测试
### 必填字段验证 ✅
| 字段 | 验证结果 |
|------|----------|
| `custIsn` (客户内码) | ✅ 不能为空 |
| `custType` (客户类型) | ✅ 不能为空 |
| `guarType` (担保方式) | ✅ 不能为空 |
| `applyAmt` (申请金额) | ✅ 不能为空 |
| `loanRate` (贷款利率) | ✅ 不能为空 |
### 字段类型验证 ✅
- 字符串字段正常接受字符串值
- 布尔字段接受 "true"/"false" 字符串
- 金额字段接受字符串格式
- 日期字段自动生成 (createTime, updateTime)
---
## 数据库验证
### 表结构 ✅
`loan_pricing_workflow` 已成功创建,包含:
- 24 个业务字段
- 4 个审计字段 (create_by, create_time, update_by, update_time)
- 主键索引 (`id`)
- 唯一索引 (`serial_num`)
- 5 个普通索引 (org_code, create_by, cust_name, update_time)
### 数据完整性 ✅
- 主键自增正常
- 唯一约束生效 (serial_num)
- 索引创建成功
- 字符集 utf8mb4 正确配置
---
## OpenAPI/Swagger 文档
### API 注册状态 ✅
| 接口 | 路径 | 标签 |
|------|------|------|
| 发起流程 | POST /loanPricing/workflow/create | 利率定价流程管理 |
| 查询列表 | GET /loanPricing/workflow/list | 利率定价流程管理 |
| 查询详情 | GET /loanPricing/workflow/{serialNum} | 利率定价流程管理 |
### 访问地址
- Swagger UI: http://localhost:8080/swagger-ui/index.html
- OpenAPI JSON: http://localhost:8080/v3/api-docs
---
## 已知问题
### 1. URL 编码问题 (低优先级)
**问题描述**: curl 测试脚本中中文参数未进行 URL 编码
**影响范围**: 仅影响测试脚本,不影响 API 功能
**解决方案**:
- 测试时使用 URL 编码或 POST + JSON body
- 前端调用时会自动处理编码,无需后端修改
---
## 测试结论
### ✅ 核心功能全部通过
利率定价流程管理的三个核心 API 接口全部测试通过:
1. **发起流程** - 支持个人和企业客户,多种担保方式
2. **查询列表** - 支持分页和多条件筛选
3. **查询详情** - 根据业务流水号查询完整信息
### ✅ 数据完整性验证通过
- 数据库表结构正确
- 索引和约束生效
- 数据自动生成 (流水号、时间戳)
### ✅ 异常处理验证通过
- 参数验证正常工作
- 必填字段检查正确
- 不存在记录正确返回错误
---
## 建议
### 前端集成建议
1. **使用 POST 方法进行复杂查询**
- 避免 URL 参数编码问题
- 支持更多筛选条件
2. **流水号显示**
- 前端创建成功后展示返回的流水号
- 支持点击流水号查看详情
3. **列表刷新**
- 创建/更新后自动刷新列表
- 保持筛选条件
### 后续优化建议
1. **添加更多筛选条件**
- 按日期范围筛选
- 按金额范围筛选
- 按利率范围筛选
2. **添加排序功能**
- 支持按创建时间排序
- 支持按金额排序
3. **添加导出功能**
- 导出为 Excel
- 支持自定义导出字段
---
## 附录
### 测试环境信息
```yaml
数据库:
主机: 116.62.17.81:40627
名称: ruoyi-test
: loan_pricing_workflow
应用:
框架: Spring Boot 3.5.8
ORM: MyBatis Plus 3.5.10
文档: SpringDoc OpenAPI 3.0
测试账号:
用户名: admin
密码: admin123
```
### 相关文件
| 文件 | 路径 |
|------|------|
| Controller | ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/controller/ |
| Service | ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/ |
| Mapper | ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/mapper/ |
| Domain | ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/ |
| SQL | sql/loan_pricing_workflow.sql |
| 测试脚本 | run-api-tests.sh |
---
**报告生成时间**: 2025-01-20 10:37:00
**测试执行者**: Claude Code AI Assistant
**测试状态**: ✅ 通过 - 核心功能全部正常工作

219
bin/restart_java_backend.sh Executable file
View File

@@ -0,0 +1,219 @@
#!/bin/sh
set -eu
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
ROOT_DIR=$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd)
LOG_DIR="$ROOT_DIR/logs"
CONSOLE_LOG="$LOG_DIR/backend-console.log"
PID_FILE="$LOG_DIR/backend-java.pid"
TARGET_DIR="$ROOT_DIR/ruoyi-admin/target"
JAR_NAME="ruoyi-admin.jar"
SERVER_PORT=8080
STOP_WAIT_SECONDS=30
APP_KEYWORD="$JAR_NAME"
JAVA_OPTS="-Duser.timezone=Asia/Shanghai -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError"
timestamp() {
date "+%Y-%m-%d %H:%M:%S"
}
log_info() {
printf '[%s] %s\n' "$(timestamp)" "$1"
}
log_error() {
printf '[%s] %s\n' "$(timestamp)" "$1" >&2
}
usage() {
cat <<'EOF'
用法: ./bin/restart_java_backend.sh [start|stop|restart|status]
默认动作:
restart 重新构建后端并重启,随后持续输出运行日志
EOF
}
ensure_command() {
if ! command -v "$1" >/dev/null 2>&1; then
log_error "缺少命令: $1"
exit 1
fi
}
collect_pids() {
all_pids=""
if [ -f "$PID_FILE" ]; then
file_pid=$(cat "$PID_FILE" 2>/dev/null || true)
if [ -n "${file_pid:-}" ] && kill -0 "$file_pid" 2>/dev/null; then
all_pids="$all_pids $file_pid"
fi
fi
port_pids=$(lsof -tiTCP:"$SERVER_PORT" -sTCP:LISTEN 2>/dev/null || true)
if [ -n "${port_pids:-}" ]; then
all_pids="$all_pids $port_pids"
fi
app_pids=$(pgrep -f "$APP_KEYWORD" 2>/dev/null || true)
if [ -n "${app_pids:-}" ]; then
all_pids="$all_pids $app_pids"
fi
unique_pids=""
for pid in $all_pids; do
case " $unique_pids " in
*" $pid "*) ;;
*)
unique_pids="$unique_pids $pid"
;;
esac
done
printf '%s\n' "$(echo "$unique_pids" | xargs 2>/dev/null || true)"
}
build_backend() {
log_info "开始构建后端: mvn -pl ruoyi-admin -am clean package -DskipTests"
(
cd "$ROOT_DIR"
mvn -pl ruoyi-admin -am clean package -DskipTests
)
}
stop_backend() {
pids=$(collect_pids)
if [ -z "${pids:-}" ]; then
log_info "未发现运行中的后端进程"
rm -f "$PID_FILE"
return 0
fi
log_info "准备停止后端进程: $pids"
for pid in $pids; do
kill -TERM "$pid" 2>/dev/null || true
done
remaining_pids="$pids"
elapsed=0
while [ -n "${remaining_pids:-}" ] && [ "$elapsed" -lt "$STOP_WAIT_SECONDS" ]; do
sleep 1
elapsed=$((elapsed + 1))
remaining_pids=""
for pid in $pids; do
if kill -0 "$pid" 2>/dev/null; then
remaining_pids="$remaining_pids $pid"
fi
done
remaining_pids=$(echo "$remaining_pids" | xargs 2>/dev/null || true)
done
if [ -n "${remaining_pids:-}" ]; then
log_info "仍有进程未退出,执行强制停止: $remaining_pids"
for pid in $remaining_pids; do
kill -KILL "$pid" 2>/dev/null || true
done
fi
rm -f "$PID_FILE"
log_info "后端停止完成"
}
start_backend() {
mkdir -p "$LOG_DIR"
touch "$CONSOLE_LOG"
printf '\n===== %s restart =====\n' "$(timestamp)" >> "$CONSOLE_LOG"
log_info "开始启动后端,控制台日志输出到: $CONSOLE_LOG"
if [ ! -f "$TARGET_DIR/$JAR_NAME" ]; then
log_error "未找到打包产物: $TARGET_DIR/$JAR_NAME"
exit 1
fi
(
cd "$TARGET_DIR"
nohup java $JAVA_OPTS -jar "$JAR_NAME" >> "$CONSOLE_LOG" 2>&1 &
echo $! > "$PID_FILE"
)
sleep 3
starter_pid=$(cat "$PID_FILE" 2>/dev/null || true)
if [ -z "${starter_pid:-}" ] || ! kill -0 "$starter_pid" 2>/dev/null; then
log_error "启动命令未保持运行,请检查日志: $CONSOLE_LOG"
exit 1
fi
log_info "启动命令已提交PID: $starter_pid"
}
status_backend() {
pids=$(collect_pids)
if [ -n "${pids:-}" ]; then
log_info "后端正在运行,进程: $pids"
else
log_info "后端未运行"
fi
}
follow_logs() {
mkdir -p "$LOG_DIR"
touch "$CONSOLE_LOG"
log_info "持续输出日志中,按 Ctrl+C 仅退出日志查看"
tail -n 200 -F "$CONSOLE_LOG"
}
start_action() {
running_pids=$(collect_pids)
if [ -n "${running_pids:-}" ]; then
log_error "检测到已有后端进程在运行: $running_pids,请先执行 stop 或 restart"
exit 1
fi
build_backend
start_backend
follow_logs
}
restart_action() {
build_backend
stop_backend
start_backend
follow_logs
}
main() {
ensure_command mvn
ensure_command lsof
ensure_command pgrep
ensure_command tail
action="${1:-restart}"
case "$action" in
start)
start_action
;;
stop)
stop_backend
;;
restart)
restart_action
;;
status)
status_backend
;;
-h|--help|help)
usage
;;
*)
usage
exit 1
;;
esac
}
main "$@"

View File

@@ -0,0 +1,20 @@
# 后端 MySQL 8.0 配置实施记录
## 本次改动
- 调整 `ruoyi-admin/src/main/resources/application-dev.yml` 的主库 JDBC 配置
- 后端继续连接 `116.62.17.81:3307/loan-pricing`
- 将连接编码从 `utf8` 调整为 `utf8mb4`
- 增加 `connectionCollation=utf8mb4_general_ci`
## 修改原因
- 当前后端已切换到 MySQL 8.0 实例 `116.62.17.81:3307`
- 当前数据库 `loan-pricing` 已统一为 `utf8mb4_general_ci`
- JDBC 连接参数需要与数据库字符集和排序规则保持一致,避免连接层与库层配置不一致
## 验证方式
- 检查 `application-dev.yml` 中 JDBC URL 已指向 `116.62.17.81:3307/loan-pricing`
- 检查 JDBC URL 已包含 `characterEncoding=utf8mb4`
- 检查 JDBC URL 已包含 `connectionCollation=utf8mb4_general_ci`

View File

@@ -0,0 +1,46 @@
# 中文数据修复实施记录
## 问题现象
- 目标库 `116.62.17.81:3307/loan-pricing` 中系统菜单、角色、用户昵称等中文字段显示为 `?`
## 根因结论
- 源库 `116.62.17.81:3306/loan-pricing` 中中文数据实际是正确的 UTF-8 字节
- 通过 `SET NAMES utf8mb4` 读取源库时,可以正确得到中文内容
- 之前生成的 `sql/loan_pricing_required_data_20260328.sql``mysqldump` 产出,文件中的中文已经被导出成问号
- 目标库乱码不是 collation 调整导致,而是导入了这份已损坏的数据 SQL
## 本次修复
- 放弃使用已损坏的 `mysqldump` 数据文件
- 直接从源库 `3306``utf8mb4` 正确读取 17 张必要数据表
- 将这 17 张表重新覆盖写入目标库 `3307`
- 重新生成 `sql/loan_pricing_required_data_20260328.sql`,确保文件内中文内容为正常 UTF-8
## 修复范围
- `loan_pricing_workflow`
- `model_corp_output_fields`
- `model_retail_output_fields`
- `sys_config`
- `sys_dept`
- `sys_dict_data`
- `sys_dict_type`
- `sys_job`
- `sys_menu`
- `sys_notice`
- `sys_post`
- `sys_role`
- `sys_role_dept`
- `sys_role_menu`
- `sys_user`
- `sys_user_post`
- `sys_user_role`
## 验证结果
- 目标库 `sys_user.nick_name` 已恢复为 `若依``测试管理员`
- 目标库 `sys_role.role_name` 已恢复为 `超级管理员``普通角色``管理员`
- 目标库 `sys_menu.menu_name` 已恢复为 `系统管理``利率定价管理``流程列表`
- 重新生成的 `sql/loan_pricing_required_data_20260328.sql` 中已包含 `管理员``若依``系统管理``用户管理``利率定价管理`

View File

@@ -0,0 +1,30 @@
# loan-pricing collation 统一实施记录
## 本次改动
- 将目标数据库 `116.62.17.81:3307/loan-pricing` 的数据库默认排序规则调整为 `utf8mb4_general_ci`
- 将目标数据库全部 33 张表的表级默认排序规则统一为 `utf8mb4_general_ci`
- 修改以下建库和建表脚本,统一默认排序规则为 `utf8mb4_general_ci`
- `sql/loan_pricing_schema_20260328.sql`
- `sql/loan_pricing_workflow.sql`
- `sql/model_corp.sql`
- `sql/model_retail.sql`
## 执行方式
1. 执行 `ALTER DATABASE \`loan-pricing\` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci`
2. 对全部现有表执行 `ALTER TABLE ... DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci`
3. 将脚本中的 `DEFAULT CHARSET=utf8mb4` 统一补齐为 `DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci`
4. 将脚本中遗留的 `utf8mb4_unicode_ci` 替换为 `utf8mb4_general_ci`
## 说明
- Quartz 相关表存在外键约束,直接执行 `CONVERT TO CHARACTER SET` 会触发外键列兼容性错误
- 因此数据库侧采用“统一数据库默认排序规则 + 统一表级默认排序规则”的方式完成所有表的 collation 统一
- 业务建表脚本已同步为 `utf8mb4_general_ci`,后续重建库时不会再回落到其他 collation
## 验证目标
- 数据库默认排序规则为 `utf8mb4_general_ci`
- 所有表的 `TABLE_COLLATION``utf8mb4_general_ci`
- 脚本中不再出现 `utf8mb4_unicode_ci`

View File

@@ -0,0 +1,70 @@
# loan-pricing 数据库迁移实施记录
## 本次改动
- 生成全量表结构 SQL: `sql/loan_pricing_schema_20260328.sql`
- 生成必要数据批量插入 SQL: `sql/loan_pricing_required_data_20260328.sql`
- 将开发环境数据库连接从 `116.62.17.81:3306` 调整为 `116.62.17.81:3307`
## 表结构 SQL 范围
- 覆盖 `loan-pricing` 库当前全部表结构
- 包含业务表、系统表、Quartz 表、代码生成相关表
## 必要数据 SQL 范围
- 业务关键表:
- `loan_pricing_workflow`
- `model_corp_output_fields`
- `model_retail_output_fields`
- 系统初始化表:
- `sys_config`
- `sys_dept`
- `sys_dict_type`
- `sys_dict_data`
- `sys_job`
- `sys_menu`
- `sys_notice`
- `sys_post`
- `sys_role`
- `sys_role_dept`
- `sys_role_menu`
- `sys_user`
- `sys_user_post`
- `sys_user_role`
## 未纳入必要数据的表
- 日志类表:
- `sys_job_log`
- `sys_logininfor`
- `sys_oper_log`
- Quartz 运行态表:
- `QRTZ_BLOB_TRIGGERS`
- `QRTZ_CALENDARS`
- `QRTZ_CRON_TRIGGERS`
- `QRTZ_FIRED_TRIGGERS`
- `QRTZ_JOB_DETAILS`
- `QRTZ_LOCKS`
- `QRTZ_PAUSED_TRIGGER_GRPS`
- `QRTZ_SCHEDULER_STATE`
- `QRTZ_SIMPLE_TRIGGERS`
- `QRTZ_SIMPROP_TRIGGERS`
- `QRTZ_TRIGGERS`
- 空表:
- `gen_table`
- `gen_table_column`
## 迁移建议
1. 在目标实例 `116.62.17.81:3307` 创建数据库 `loan-pricing`
2. 执行 `sql/loan_pricing_schema_20260328.sql`
3. 执行 `sql/loan_pricing_required_data_20260328.sql`
4. 启动项目并验证后台登录、字典加载、利率定价流程页面和任务配置
## 验证记录
- 使用 `mysqldump --no-data` 导出了全部表结构
- 使用 `mysqldump --no-create-info --complete-insert --extended-insert` 导出了必要数据
- 已更新 `ruoyi-admin/src/main/resources/application-dev.yml` 中的主库连接地址
- 已在 `116.62.17.81:3307` 实际执行表结构导入和必要数据导入

View File

@@ -0,0 +1,22 @@
# restart_java_backend.sh 实施记录
## 本次改动
- 调整 `bin/restart_java_backend.sh` 中的后端监听端口,从旧的 `62318` 改为当前项目 `ruoyi-admin``dev` 环境下实际使用的 `8080`
## 修改原因
- 当前项目后端默认启动配置位于 `ruoyi-admin/src/main/resources/application-dev.yml`
- 该配置的 `server.port``8080`
- 原脚本继续使用旧端口会导致 `status``stop``restart` 无法准确识别当前正在运行的 Java 后端进程
## 影响说明
- `collect_pids` 现在会基于正确端口识别后端监听进程
- `start` 前的运行态判断会更准确
- `stop``restart` 会正确处理当前项目启动出的后端服务
## 验证方式
- 执行 `sh -n bin/restart_java_backend.sh` 校验脚本语法
- 执行 `bin/restart_java_backend.sh status` 验证脚本可正常读取当前后端状态

View File

@@ -1,75 +0,0 @@
# 修复中文乱码问题
## 问题原因
1. 数据库连接 URL 使用的是 `characterEncoding=utf8` 而不是 `utf8mb4`
2. 已插入的数据使用错误的编码保存
## 解决步骤
### 步骤 1: 清理乱码数据
在数据库中执行:
```sql
-- 删除表中的乱码数据
DELETE FROM loan_pricing_workflow;
```
或删除表重建:
```sql
DROP TABLE IF EXISTS `loan_pricing_workflow`;
-- 然后重新执行 sql/loan_pricing_workflow.sql
```
### 步骤 2: 重启服务
配置文件已更新,需要重启后端服务使配置生效:
```bash
# 停止当前服务
pkill -f "ruoyi-admin.jar"
# 重新打包(可选,如果没有修改代码)
cd d:\利率定价\loan-pricing-892\loan-pricing-892-v2.0
mvn clean package -Dmaven.test.skip=true
# 启动服务
cd ruoyi-admin/target
java -jar ruoyi-admin.jar
```
### 步骤 3: 重新执行测试
```bash
cd d:\利率定价\loan-pricing-892\loan-pricing-892-v2.0
bash run-api-tests.sh
```
## 配置说明
已修改的配置文件:`ruoyi-admin/src/main/resources/application-dev.yml`
修改前:
```yaml
url: jdbc:mysql://...?useUnicode=true&characterEncoding=utf8&...
```
修改后:
```yaml
url: jdbc:mysql://...?useUnicode=true&characterEncoding=utf8mb4&...
```
## 验证方法
重启服务并插入新数据后,检查数据库:
```sql
SELECT serial_num, cust_name, cust_type, guar_type FROM loan_pricing_workflow;
```
中文应该正常显示,例如:
- cust_name: "张三" (而不是乱码)
- cust_type: "个人" (而不是乱码)
- guar_type: "信用" (而不是乱码)

View File

@@ -1,456 +0,0 @@
# OpenSpec Instructions
Instructions for AI coding assistants using OpenSpec for spec-driven development.
## TL;DR Quick Checklist
- Search existing work: `openspec spec list --long`, `openspec list` (use `rg` only for full-text search)
- Decide scope: new capability vs modify existing capability
- Pick a unique `change-id`: kebab-case, verb-led (`add-`, `update-`, `remove-`, `refactor-`)
- Scaffold: `proposal.md`, `tasks.md`, `design.md` (only if needed), and delta specs per affected capability
- Write deltas: use `## ADDED|MODIFIED|REMOVED|RENAMED Requirements`; include at least one `#### Scenario:` per requirement
- Validate: `openspec validate [change-id] --strict --no-interactive` and fix issues
- Request approval: Do not start implementation until proposal is approved
## Three-Stage Workflow
### Stage 1: Creating Changes
Create proposal when you need to:
- Add features or functionality
- Make breaking changes (API, schema)
- Change architecture or patterns
- Optimize performance (changes behavior)
- Update security patterns
Triggers (examples):
- "Help me create a change proposal"
- "Help me plan a change"
- "Help me create a proposal"
- "I want to create a spec proposal"
- "I want to create a spec"
Loose matching guidance:
- Contains one of: `proposal`, `change`, `spec`
- With one of: `create`, `plan`, `make`, `start`, `help`
Skip proposal for:
- Bug fixes (restore intended behavior)
- Typos, formatting, comments
- Dependency updates (non-breaking)
- Configuration changes
- Tests for existing behavior
**Workflow**
1. Review `openspec/project.md`, `openspec list`, and `openspec list --specs` to understand current context.
2. Choose a unique verb-led `change-id` and scaffold `proposal.md`, `tasks.md`, optional `design.md`, and spec deltas under `openspec/changes/<id>/`.
3. Draft spec deltas using `## ADDED|MODIFIED|REMOVED Requirements` with at least one `#### Scenario:` per requirement.
4. Run `openspec validate <id> --strict --no-interactive` and resolve any issues before sharing the proposal.
### Stage 2: Implementing Changes
Track these steps as TODOs and complete them one by one.
1. **Read proposal.md** - Understand what's being built
2. **Read design.md** (if exists) - Review technical decisions
3. **Read tasks.md** - Get implementation checklist
4. **Implement tasks sequentially** - Complete in order
5. **Confirm completion** - Ensure every item in `tasks.md` is finished before updating statuses
6. **Update checklist** - After all work is done, set every task to `- [x]` so the list reflects reality
7. **Approval gate** - Do not start implementation until the proposal is reviewed and approved
### Stage 3: Archiving Changes
After deployment, create separate PR to:
- Move `changes/[name]/``changes/archive/YYYY-MM-DD-[name]/`
- Update `specs/` if capabilities changed
- Use `openspec archive <change-id> --skip-specs --yes` for tooling-only changes (always pass the change ID explicitly)
- Run `openspec validate --strict --no-interactive` to confirm the archived change passes checks
## Before Any Task
**Context Checklist:**
- [ ] Read relevant specs in `specs/[capability]/spec.md`
- [ ] Check pending changes in `changes/` for conflicts
- [ ] Read `openspec/project.md` for conventions
- [ ] Run `openspec list` to see active changes
- [ ] Run `openspec list --specs` to see existing capabilities
**Before Creating Specs:**
- Always check if capability already exists
- Prefer modifying existing specs over creating duplicates
- Use `openspec show [spec]` to review current state
- If request is ambiguous, ask 12 clarifying questions before scaffolding
### Search Guidance
- Enumerate specs: `openspec spec list --long` (or `--json` for scripts)
- Enumerate changes: `openspec list` (or `openspec change list --json` - deprecated but available)
- Show details:
- Spec: `openspec show <spec-id> --type spec` (use `--json` for filters)
- Change: `openspec show <change-id> --json --deltas-only`
- Full-text search (use ripgrep): `rg -n "Requirement:|Scenario:" openspec/specs`
## Quick Start
### CLI Commands
```bash
# Essential commands
openspec list # List active changes
openspec list --specs # List specifications
openspec show [item] # Display change or spec
openspec validate [item] # Validate changes or specs
openspec archive <change-id> [--yes|-y] # Archive after deployment (add --yes for non-interactive runs)
# Project management
openspec init [path] # Initialize OpenSpec
openspec update [path] # Update instruction files
# Interactive mode
openspec show # Prompts for selection
openspec validate # Bulk validation mode
# Debugging
openspec show [change] --json --deltas-only
openspec validate [change] --strict --no-interactive
```
### Command Flags
- `--json` - Machine-readable output
- `--type change|spec` - Disambiguate items
- `--strict` - Comprehensive validation
- `--no-interactive` - Disable prompts
- `--skip-specs` - Archive without spec updates
- `--yes`/`-y` - Skip confirmation prompts (non-interactive archive)
## Directory Structure
```
openspec/
├── project.md # Project conventions
├── specs/ # Current truth - what IS built
│ └── [capability]/ # Single focused capability
│ ├── spec.md # Requirements and scenarios
│ └── design.md # Technical patterns
├── changes/ # Proposals - what SHOULD change
│ ├── [change-name]/
│ │ ├── proposal.md # Why, what, impact
│ │ ├── tasks.md # Implementation checklist
│ │ ├── design.md # Technical decisions (optional; see criteria)
│ │ └── specs/ # Delta changes
│ │ └── [capability]/
│ │ └── spec.md # ADDED/MODIFIED/REMOVED
│ └── archive/ # Completed changes
```
## Creating Change Proposals
### Decision Tree
```
New request?
├─ Bug fix restoring spec behavior? → Fix directly
├─ Typo/format/comment? → Fix directly
├─ New feature/capability? → Create proposal
├─ Breaking change? → Create proposal
├─ Architecture change? → Create proposal
└─ Unclear? → Create proposal (safer)
```
### Proposal Structure
1. **Create directory:** `changes/[change-id]/` (kebab-case, verb-led, unique)
2. **Write proposal.md:**
```markdown
# Change: [Brief description of change]
## Why
[1-2 sentences on problem/opportunity]
## What Changes
- [Bullet list of changes]
- [Mark breaking changes with **BREAKING**]
## Impact
- Affected specs: [list capabilities]
- Affected code: [key files/systems]
```
3. **Create spec deltas:** `specs/[capability]/spec.md`
```markdown
## ADDED Requirements
### Requirement: New Feature
The system SHALL provide...
#### Scenario: Success case
- **WHEN** user performs action
- **THEN** expected result
## MODIFIED Requirements
### Requirement: Existing Feature
[Complete modified requirement]
## REMOVED Requirements
### Requirement: Old Feature
**Reason**: [Why removing]
**Migration**: [How to handle]
```
If multiple capabilities are affected, create multiple delta files under `changes/[change-id]/specs/<capability>/spec.md`—one per capability.
4. **Create tasks.md:**
```markdown
## 1. Implementation
- [ ] 1.1 Create database schema
- [ ] 1.2 Implement API endpoint
- [ ] 1.3 Add frontend component
- [ ] 1.4 Write tests
```
5. **Create design.md when needed:**
Create `design.md` if any of the following apply; otherwise omit it:
- Cross-cutting change (multiple services/modules) or a new architectural pattern
- New external dependency or significant data model changes
- Security, performance, or migration complexity
- Ambiguity that benefits from technical decisions before coding
Minimal `design.md` skeleton:
```markdown
## Context
[Background, constraints, stakeholders]
## Goals / Non-Goals
- Goals: [...]
- Non-Goals: [...]
## Decisions
- Decision: [What and why]
- Alternatives considered: [Options + rationale]
## Risks / Trade-offs
- [Risk] → Mitigation
## Migration Plan
[Steps, rollback]
## Open Questions
- [...]
```
## Spec File Format
### Critical: Scenario Formatting
**CORRECT** (use #### headers):
```markdown
#### Scenario: User login success
- **WHEN** valid credentials provided
- **THEN** return JWT token
```
**WRONG** (don't use bullets or bold):
```markdown
- **Scenario: User login** ❌
**Scenario**: User login ❌
### Scenario: User login ❌
```
Every requirement MUST have at least one scenario.
### Requirement Wording
- Use SHALL/MUST for normative requirements (avoid should/may unless intentionally non-normative)
### Delta Operations
- `## ADDED Requirements` - New capabilities
- `## MODIFIED Requirements` - Changed behavior
- `## REMOVED Requirements` - Deprecated features
- `## RENAMED Requirements` - Name changes
Headers matched with `trim(header)` - whitespace ignored.
#### When to use ADDED vs MODIFIED
- ADDED: Introduces a new capability or sub-capability that can stand alone as a requirement. Prefer ADDED when the change is orthogonal (e.g., adding "Slash Command Configuration") rather than altering the semantics of an existing requirement.
- MODIFIED: Changes the behavior, scope, or acceptance criteria of an existing requirement. Always paste the full, updated requirement content (header + all scenarios). The archiver will replace the entire requirement with what you provide here; partial deltas will drop previous details.
- RENAMED: Use when only the name changes. If you also change behavior, use RENAMED (name) plus MODIFIED (content) referencing the new name.
Common pitfall: Using MODIFIED to add a new concern without including the previous text. This causes loss of detail at archive time. If you arent explicitly changing the existing requirement, add a new requirement under ADDED instead.
Authoring a MODIFIED requirement correctly:
1) Locate the existing requirement in `openspec/specs/<capability>/spec.md`.
2) Copy the entire requirement block (from `### Requirement: ...` through its scenarios).
3) Paste it under `## MODIFIED Requirements` and edit to reflect the new behavior.
4) Ensure the header text matches exactly (whitespace-insensitive) and keep at least one `#### Scenario:`.
Example for RENAMED:
```markdown
## RENAMED Requirements
- FROM: `### Requirement: Login`
- TO: `### Requirement: User Authentication`
```
## Troubleshooting
### Common Errors
**"Change must have at least one delta"**
- Check `changes/[name]/specs/` exists with .md files
- Verify files have operation prefixes (## ADDED Requirements)
**"Requirement must have at least one scenario"**
- Check scenarios use `#### Scenario:` format (4 hashtags)
- Don't use bullet points or bold for scenario headers
**Silent scenario parsing failures**
- Exact format required: `#### Scenario: Name`
- Debug with: `openspec show [change] --json --deltas-only`
### Validation Tips
```bash
# Always use strict mode for comprehensive checks
openspec validate [change] --strict --no-interactive
# Debug delta parsing
openspec show [change] --json | jq '.deltas'
# Check specific requirement
openspec show [spec] --json -r 1
```
## Happy Path Script
```bash
# 1) Explore current state
openspec spec list --long
openspec list
# Optional full-text search:
# rg -n "Requirement:|Scenario:" openspec/specs
# rg -n "^#|Requirement:" openspec/changes
# 2) Choose change id and scaffold
CHANGE=add-two-factor-auth
mkdir -p openspec/changes/$CHANGE/{specs/auth}
printf "## Why\n...\n\n## What Changes\n- ...\n\n## Impact\n- ...\n" > openspec/changes/$CHANGE/proposal.md
printf "## 1. Implementation\n- [ ] 1.1 ...\n" > openspec/changes/$CHANGE/tasks.md
# 3) Add deltas (example)
cat > openspec/changes/$CHANGE/specs/auth/spec.md << 'EOF'
## ADDED Requirements
### Requirement: Two-Factor Authentication
Users MUST provide a second factor during login.
#### Scenario: OTP required
- **WHEN** valid credentials are provided
- **THEN** an OTP challenge is required
EOF
# 4) Validate
openspec validate $CHANGE --strict --no-interactive
```
## Multi-Capability Example
```
openspec/changes/add-2fa-notify/
├── proposal.md
├── tasks.md
└── specs/
├── auth/
│ └── spec.md # ADDED: Two-Factor Authentication
└── notifications/
└── spec.md # ADDED: OTP email notification
```
auth/spec.md
```markdown
## ADDED Requirements
### Requirement: Two-Factor Authentication
...
```
notifications/spec.md
```markdown
## ADDED Requirements
### Requirement: OTP Email Notification
...
```
## Best Practices
### Simplicity First
- Default to <100 lines of new code
- Single-file implementations until proven insufficient
- Avoid frameworks without clear justification
- Choose boring, proven patterns
### Complexity Triggers
Only add complexity with:
- Performance data showing current solution too slow
- Concrete scale requirements (>1000 users, >100MB data)
- Multiple proven use cases requiring abstraction
### Clear References
- Use `file.ts:42` format for code locations
- Reference specs as `specs/auth/spec.md`
- Link related changes and PRs
### Capability Naming
- Use verb-noun: `user-auth`, `payment-capture`
- Single purpose per capability
- 10-minute understandability rule
- Split if description needs "AND"
### Change ID Naming
- Use kebab-case, short and descriptive: `add-two-factor-auth`
- Prefer verb-led prefixes: `add-`, `update-`, `remove-`, `refactor-`
- Ensure uniqueness; if taken, append `-2`, `-3`, etc.
## Tool Selection Guide
| Task | Tool | Why |
|------|------|-----|
| Find files by pattern | Glob | Fast pattern matching |
| Search code content | Grep | Optimized regex search |
| Read specific files | Read | Direct file access |
| Explore unknown scope | Task | Multi-step investigation |
## Error Recovery
### Change Conflicts
1. Run `openspec list` to see active changes
2. Check for overlapping specs
3. Coordinate with change owners
4. Consider combining proposals
### Validation Failures
1. Run with `--strict` flag
2. Check JSON output for details
3. Verify spec file format
4. Ensure scenarios properly formatted
### Missing Context
1. Read project.md first
2. Check related specs
3. Review recent archives
4. Ask for clarification
## Quick Reference
### Stage Indicators
- `changes/` - Proposed, not yet built
- `specs/` - Built and deployed
- `archive/` - Completed changes
### File Purposes
- `proposal.md` - Why and what
- `tasks.md` - Implementation steps
- `design.md` - Technical decisions
- `spec.md` - Requirements and behavior
### CLI Essentials
```bash
openspec list # What's in progress?
openspec show [item] # View details
openspec validate --strict --no-interactive # Is it correct?
openspec archive <change-id> [--yes|-y] # Mark complete (add --yes for automation)
```
Remember: Specs are truth. Changes are proposals. Keep them in sync.

View File

@@ -1,186 +0,0 @@
# Design: 议价池显示组件
## Overview
本文档描述议价池显示组件的详细设计,包括组件结构、数据流、样式规范和实现细节。
## Component Architecture
### 组件层次结构
```
detail.vue (流程详情页面)
├── left-panel (左侧关键信息卡片)
└── right-panel (右侧面板)
├── detail-card (流程详情卡片)
├── ModelOutputDisplay (模型输出组件) [已存在]
└── BargainingPoolDisplay (议价池显示组件) [新增]
```
### 组件职责
| 组件 | 职责 |
|------|------|
| `detail.vue` | 流程详情页面容器,负责数据获取和子组件协调 |
| `BargainingPoolDisplay.vue` | 议价池数据展示,独立封装议价池相关的 UI 和逻辑 |
## Component Specification
### BargainingPoolDisplay.vue
#### Props
| 属性名 | 类型 | 默认值 | 说明 |
|--------|------|--------|------|
| `branchPool` | Number/String | 0 | 网点议价池 |
| `subBranchPool` | Number/String | 0 | 支行议价池 |
| `privateDomainPool` | Number/String | 0 | 私域池 |
#### Template Structure
```vue
<template>
<el-card class="bargaining-pool-card">
<div slot="header" class="card-header">
<span class="card-title">议价池</span>
</div>
<el-descriptions :column="3" border size="small">
<el-descriptions-item label="网点议价池">
{{ displayBranchPool }}
</el-descriptions-item>
<el-descriptions-item label="支行议价池">
{{ displaySubBranchPool }}
</el-descriptions-item>
<el-descriptions-item label="私域池">
{{ displayPrivateDomainPool }}
</el-descriptions-item>
</el-descriptions>
</el-card>
</template>
```
#### Computed Properties
| 属性名 | 说明 |
|--------|------|
| `displayBranchPool` | 返回网点议价池的显示值,处理 null/undefined/空字符串为 '0' |
| `displaySubBranchPool` | 返回支行议价池的显示值,处理 null/undefined/空字符串为 '0' |
| `displayPrivateDomainPool` | 返回私域池的显示值,处理 null/undefined/空字符串为 '0' |
#### Style Specification
议价池卡片样式将与 `ModelOutputDisplay` 保持一致:
```scss
.bargaining-pool-card {
// 与 model-output-card 相同的样式
::v-deep .el-card__header {
padding: 16px 20px;
background-color: #fafafa;
border-bottom: 1px solid #ebeef5;
}
.card-header {
display: flex;
align-items: center;
.card-title {
font-size: 16px;
font-weight: 500;
color: #303133;
}
}
::v-deep .el-card__body {
padding: 20px;
}
}
```
## Data Flow
### API 响应结构(预期)
```javascript
{
"data": {
"loanPricingWorkflow": { ... },
"modelRetailOutputFields": { ... },
"modelCorpOutputFields": { ... },
"bargainingPool": { // 新增字段
"branchPool": 10, // 网点议价池
"subBranchPool": 5, // 支行议价池
"privateDomainPool": 3 // 私域池
}
}
}
```
### 组件集成
`detail.vue` 中:
```javascript
// data
bargainingPool: null,
// created() 中获取数据
getWorkflow(serialNum).then(response => {
this.workflowDetail = response.data.loanPricingWorkflow
this.retailOutput = response.data.modelRetailOutputFields
this.corpOutput = response.data.modelCorpOutputFields
this.bargainingPool = response.data.bargainingPool // 新增
this.loading = false
})
```
```vue
<!-- template 中使用组件 -->
<BargainingPoolDisplay
:branch-pool="bargainingPool?.branchPool"
:sub-branch-pool="bargainingPool?.subBranchPool"
:private-domain-pool="bargainingPool?.privateDomainPool"
/>
```
## Error Handling
### 数据缺失处理
当 API 响应中没有议价池数据时:
- 组件使用默认值 0 显示
- 不显示错误提示
- 保证页面正常展示
### 值格式化
```javascript
computed: {
displayBranchPool() {
const value = this.branchPool
if (value === null || value === undefined || value === '') {
return '0'
}
return value
},
// ... 其他字段类似
}
```
## Testing Considerations
### 单元测试场景
1. 组件渲染时显示默认值 0
2. 传入正确的议价池数据时正确显示
3. 处理 null/undefined 值时显示 0
### 集成测试场景
1. 流程详情页面加载时议价池卡片正确显示
2. 议价池卡片位置在模型输出卡片下方
3. 样式与模型输出卡片保持一致
## Future Enhancements
1. **后端数据对接**:当后端提供议价池 API 时,移除默认值逻辑
2. **单位显示**确认议价池数值单位BP 或金额)后添加单位标签
3. **交互功能**:可能需要添加议价池的编辑或调整功能

View File

@@ -1,85 +0,0 @@
# Proposal: 添加议价池显示组件
## Summary
在流程详情页面中,在"模型输出"卡片下方添加一个新的"议价池"卡片,用于展示网点议价池、支行议价池和私域池三个字段。默认值均为 0。
## Motivation
当前流程详情页面展示了模型输出的详细信息,但缺少议价池相关的数据展示。议价池是贷款定价业务中的重要参考指标,需要将其添加到详情页面以便用户查看。
## Proposed Change
### Scope
仅修改前端流程详情页面,在模型输出组件下方添加议价池显示组件。
### Components Affected
- `ruoyi-ui/src/views/loanPricing/workflow/detail.vue` - 添加议价池组件
### Components to Create
- `ruoyi-ui/src/views/loanPricing/workflow/components/BargainingPoolDisplay.vue` - 新建议价池显示组件
## Design Approach
### UI 结构
议价池卡片将使用与模型输出卡片相同的样式风格,包含:
- 卡片标题:议价池
- 三个字段展示:
- 网点议价池默认值0
- 支行议价池默认值0
- 私域池默认值0
### 组件设计
- 创建独立的 `BargainingPoolDisplay.vue` 组件
- 使用 `el-descriptions` 组件展示字段
- 支持通过 props 传入议价池数据
- 默认值处理:当数据为空或未定义时显示 0
### 数据来源
- 议价池数据将从后端 API 响应中获取
- 暂时使用默认值 0后续由后端提供实际数据
## Alternatives Considered
1. **将议价池字段添加到模型输出组件内部**
- 优点:减少组件数量
- 缺点:模型输出组件已比较复杂,议价池是独立的业务概念,应独立展示
- 结论:不采用
2. **将议价池字段添加到流程详情卡片中**
- 优点:集中展示流程相关信息
- 缺点:议价池与流程基本信息关联性较弱,与模型输出更相关
- 结论:不采用
3. **创建独立的议价池组件(已选方案)**
- 优点:职责清晰、易于维护、与模型输出组件并列展示
- 缺点:增加一个组件文件
- 结论:采用
## Dependencies
- 依赖现有的 `el-card``el-descriptions` 组件
- 依赖后端 API 返回议价池数据(当前可使用默认值)
## Rollout Plan
1. 创建 `BargainingPoolDisplay.vue` 组件
2.`detail.vue` 中引入并使用该组件
3. 传递议价池数据(当前使用默认值)
4. 测试页面展示效果
## Success Criteria
- 议价池卡片正确显示在模型输出卡片下方
- 三个字段(网点议价池、支行议价池、私域池)正确显示
- 默认值显示为 0
- 样式与现有卡片保持一致
## Open Questions
1. 议价池数据的具体字段名称是什么?
- 待确认:后端 API 中的议价池字段命名
2. 议价池数据的数值类型和单位是什么?
- 假设为数值类型BP 或金额)
- 待后端确认

View File

@@ -1,42 +0,0 @@
# loan-pricing-workflow-ui Spec Delta
## ADDED Requirements
### Requirement: 议价池信息展示
系统 SHALL 在流程详情页面的模型输出信息下方展示议价池信息。
#### Scenario: 显示议价池信息
- **WHEN** 用户访问流程详情页面
- **THEN** 系统在模型输出卡片下方显示"议价池"卡片,包含以下三个字段:
- 网点议价池:数值类型,默认值为 0
- 支行议价池:数值类型,默认值为 0
- 私域池:数值类型,默认值为 0
#### Scenario: 议价池数据格式化
- **WHEN** 议价池数据为 null、undefined 或空字符串
- **THEN** 系统将显示值格式化为 "0"
#### Scenario: 议价池卡片样式
- **WHEN** 用户查看流程详情页面
- **THEN** 议价池卡片的样式(标题栏、边框、内边距)与模型输出卡片保持一致
### Requirement: 议价池组件封装
系统 SHALL 将议价池展示功能封装为独立的 Vue 组件。
#### Scenario: 组件独立性
- **WHEN** 议价池显示组件被创建
- **THEN** 组件文件位于 `ruoyi-ui/src/views/loanPricing/workflow/components/BargainingPoolDisplay.vue`
#### Scenario: 组件 Props 接口
- **WHEN** 父组件使用议价池显示组件
- **THEN** 组件接收以下 props
- `branch-pool`网点议价池值Number/String默认值为 0
- `sub-branch-pool`支行议价池值Number/String默认值为 0
- `private-domain-pool`私域池值Number/String默认值为 0

View File

@@ -1,68 +0,0 @@
# Tasks: 添加议价池显示组件
## Task List
### 1. 创建议价池显示组件 ✅
**文件**: `ruoyi-ui/src/views/loanPricing/workflow/components/BargainingPoolDisplay.vue`
**描述**: 创建新的 Vue 组件用于展示议价池信息
**验收标准**:
- [x] 组件使用 `el-card` 包装,标题为"议价池"
- [x] 使用 `el-descriptions` 展示三个字段:网点议价池、支行议价池、私域池
- [x] 定义 props`branchPool``subBranchPool``privateDomainPool`,默认值为 0
- [x] 实现计算属性处理 null/undefined/空字符串,返回 '0'
- [x] 样式与 `ModelOutputDisplay` 保持一致
**依赖**: 无
---
### 2. 在详情页面中引入并使用议价池组件 ✅
**文件**: `ruoyi-ui/src/views/loanPricing/workflow/detail.vue`
**描述**: 在流程详情页面中引入并配置议价池组件
**验收标准**:
- [x]`components` 中注册 `BargainingPoolDisplay` 组件
- [x]`data` 中添加 `bargainingPool: null`
- [x]`getDetail()` 方法中从 API 响应获取议价池数据:`response.data.bargainingPool`
- [x] 在 template 中,`ModelOutputDisplay` 组件下方添加 `BargainingPoolDisplay` 组件
- [x] 传递 props`:branch-pool``:sub-branch-pool``:private-domain-pool`
**依赖**: Task 1
---
### 3. 验证页面展示效果 ✅
**描述**: 启动前端开发服务器,验证议价池组件正确显示
**验收标准**:
- [x] 访问任意流程详情页面
- [x] 确认议价池卡片显示在模型输出卡片下方
- [x] 确认三个字段显示为 "0"(默认值)
- [x] 确认卡片样式与模型输出卡片一致
**依赖**: Task 1, Task 2
---
## Dependencies Graph
```
Task 1 (创建组件) ✅
Task 2 (集成到详情页) ✅
Task 3 (验证效果) ✅
```
## Implementation Notes
- 使用 `&&` 操作符替代可选链 `?.` 以兼容 Vue 2.6
- 构建验证通过 (`npm run build:prod` 完成)
## Notes
- 当前使用默认值 0后续后端提供议价池 API 后需要更新数据获取逻辑
- 议价池数值的单位BP 或金额)尚未确认,暂不添加单位标签

View File

@@ -1,45 +0,0 @@
# 提案: 添加执行利率设定前端功能
## 背景
后端已经实现了执行利率设定接口 `PUT /loanPricing/workflow/{serialNum}/executeRate`,并且详情接口 `GET /loanPricing/workflow/{serialNum}` 已经返回 `executeRate` 字段。但前端缺少相应的 UI 交互功能,业务人员无法通过界面设定执行利率。
## 问题
1. 议价池组件中只显示议价池数据,没有执行利率输入框
2. 前端缺少调用设定执行利率接口的 API 方法
3. 用户无法通过界面设定或更新执行利率
## 提案概述
在流程详情页面的议价池组件中添加执行利率设定功能,允许业务人员输入执行利率并提交。
### 功能范围
1. **API 方法**
-`ruoyi-ui/src/api/loanPricing/workflow.js` 中添加 `setExecuteRate` 方法
2. **议价池组件更新**
-`BargainingPoolDisplay.vue` 中添加执行利率输入框和提交按钮
- 添加执行利率显示/编辑状态的切换
- 支持显示已设定的执行利率值
- 添加表单验证(利率格式)
3. **详情页面更新**
-`detail.vue` 中传递 `executeRate``serialNum` 给议价池组件
- 添加提交成功后刷新详情的处理
## 影响范围
- 前端 API: `ruoyi-ui/src/api/loanPricing/workflow.js`
- 前端组件: `ruoyi-ui/src/views/loanPricing/workflow/components/BargainingPoolDisplay.vue`
- 前端页面: `ruoyi-ui/src/views/loanPricing/workflow/detail.vue`
- 规范: `loan-pricing-workflow-ui` (添加新需求)
## 设计考虑
1. **UI 位置**: 在议价池组件中添加新行,保持与现有议价池数据显示的一致性
2. **输入验证**: 利率格式验证(数字,可含小数点,范围合理)
3. **状态管理**: 编辑/查看状态切换,提交成功后显示最新值
4. **用户反馈**: 提交成功/失败的提示消息
5. **权限控制**: 后端接口无需特殊权限,前端暂不添加权限控制

View File

@@ -1,45 +0,0 @@
## ADDED Requirements
### Requirement: 执行利率设定
系统 SHALL 在流程详情页面的议价池组件中提供执行利率设定功能,允许用户输入并提交执行利率。
#### Scenario: 显示未设定的执行利率
- **WHEN** 用户在流程详情页面查看议价池组件,且该流程尚未设定执行利率
- **THEN** 系统在议价池组件中显示"执行利率"行,当前值显示为"-"
#### Scenario: 显示已设定的执行利率
- **WHEN** 用户在流程详情页面查看议价池组件,且该流程已设定执行利率
- **THEN** 系统在议价池组件中显示"执行利率"行,显示当前设定的执行利率值
#### Scenario: 进入编辑模式
- **WHEN** 用户在议价池组件中点击"执行利率"行的编辑按钮
- **THEN** 系统切换到编辑模式,显示输入框(预填充当前值或空)、提交按钮和取消按钮
#### Scenario: 提交执行利率成功
- **WHEN** 用户在编辑模式下输入有效的执行利率值并点击提交按钮
- **THEN** 系统调用 `PUT /loanPricing/workflow/{serialNum}/executeRate` 接口,成功后更新显示值为新设定的利率,显示成功提示消息,并退出编辑模式
#### Scenario: 提交执行利率失败
- **WHEN** 用户在编辑模式下提交执行利率,但后端接口返回错误
- **THEN** 系统保持编辑模式,显示错误提示消息
#### Scenario: 取消编辑
- **WHEN** 用户在编辑模式下点击取消按钮
- **THEN** 系统退出编辑模式,恢复显示模式,显示原来的执行利率值
#### Scenario: 输入验证
- **WHEN** 用户在编辑模式下输入非法的执行利率值(非数字、超出合理范围)
- **THEN** 系统在提交前进行验证,显示错误提示,阻止提交
#### Scenario: API 接口调用
- **WHEN** 用户提交执行利率
- **THEN** 前端调用 `setExecuteRate(serialNum, executeRate)` API 方法,该方法发送 `PUT /loanPricing/workflow/{serialNum}/executeRate` 请求

View File

@@ -1,85 +0,0 @@
# 实施任务
## 任务清单
1. **添加 API 方法**
- 文件: `ruoyi-ui/src/api/loanPricing/workflow.js`
- 操作: 添加 `setExecuteRate(serialNum, executeRate)` 方法
- 请求: `PUT /loanPricing/workflow/{serialNum}/executeRate`
- 验证: 方法添加成功
2. **更新议价池组件 - Props**
- 文件: `ruoyi-ui/src/views/loanPricing/workflow/components/BargainingPoolDisplay.vue`
- 操作: 添加 `executeRate``serialNum` props
- 验证: props 定义成功
3. **更新议价池组件 - UI**
- 文件: `ruoyi-ui/src/views/loanPricing/workflow/components/BargainingPoolDisplay.vue`
- 操作: 在 el-descriptions 中添加"执行利率"行,包含:
- 显示模式: 显示当前执行利率值(若无则显示"-"
- 编辑模式: 输入框 + 提交按钮 + 取消按钮
- 编辑按钮: 在显示模式下点击进入编辑模式
- 验证: UI 更新成功
4. **更新议价池组件 - 数据和逻辑**
- 文件: `ruoyi-ui/src/views/loanPricing/workflow/components/BargainingPoolDisplay.vue`
- 操作:
- 添加 `isEditing` 状态变量
- 添加 `tempExecuteRate` 临时输入值
- 添加 `handleEdit` 方法进入编辑模式
- 添加 `handleSubmit` 方法调用 API 并处理响应
- 添加 `handleCancel` 方法取消编辑
- 添加输入验证(数字格式、范围检查)
- 验证: 逻辑实现完整
5. **更新议价池组件 - API 调用**
- 文件: `ruoyi-ui/src/views/loanPricing/workflow/components/BargainingPoolDisplay.vue`
- 操作: 引入 `setExecuteRate` API 方法
- 验证: 引入成功
6. **更新详情页面 - 传递 Props**
- 文件: `ruoyi-ui/src/views/loanPricing/workflow/detail.vue`
- 操作: 在 BargainingPoolDisplay 组件上传递:
- `:execute-rate="workflowDetail.executeRate"`
- `:serial-num="workflowDetail.serialNum"`
- `@execute-rate-updated="handleExecuteRateUpdated"`
- 验证: props 传递正确
7. **前端功能验证**
- 操作:
- 启动前端服务
- 打开流程详情页面
- 测试首次设定执行利率
- 测试更新已设定的执行利率
- 测试输入验证
- 测试取消编辑
- 验证:
- 未设定时显示"-"
- 已设定时显示当前值
- 点击编辑按钮进入编辑模式
- 输入框显示当前值
- 提交成功后显示新值并显示成功提示
- 取消编辑恢复显示模式
- 输入非法值时显示错误提示
## 依赖关系
- 任务 1 必须首先执行API 方法)
- 任务 2-5 依次执行Props -> UI -> 数据逻辑 -> API 调用)
- 任务 6 依赖任务 2
- 任务 7 在所有代码任务完成后执行
## 验收标准
- [x] API 方法 `setExecuteRate` 添加成功
- [x] 议价池组件添加 `executeRate``serialNum` props
- [x] 议价池组件显示执行利率行
- [x] 未设定时显示"-"
- [x] 已设定时显示当前值
- [x] 编辑按钮切换到编辑模式
- [x] 输入框显示当前值
- [x] 提交按钮调用 API 成功
- [x] 提交成功后更新显示并显示成功提示
- [x] 取消按钮恢复显示模式
- [x] 输入验证正确工作
- [x] 详情页面正确传递 props

View File

@@ -1,153 +0,0 @@
# 设计文档: 执行利率设定接口
## 数据库设计
### 表结构变更
**表名**: `loan_pricing_workflow`
**新增字段**:
| 字段名 | 类型 | 可空 | 默认值 | 说明 |
|--------------|-------------|----|------|---------|
| execute_rate | varchar(20) | 是 | NULL | 执行利率(%) |
**DDL**:
```sql
ALTER TABLE `loan_pricing_workflow`
ADD COLUMN `execute_rate` varchar(20) DEFAULT NULL COMMENT '执行利率(%)' AFTER `loan_rate`;
```
## 接口设计
### 设定执行利率接口
**请求方式**: `PUT /loanPricing/workflow/{serialNum}/executeRate`
**权限要求**: 无特殊权限要求(与查询接口一致)
**路径参数**:
| 参数名 | 类型 | 必填 | 说明 |
|-----------|--------|----|--------|
| serialNum | String | 是 | 业务方流水号 |
**请求体**:
```json
{
"executeRate": "4.20"
}
```
**参数说明**:
| 参数名 | 类型 | 必填 | 说明 |
|-------------|--------|----|----------------------|
| executeRate | String | 是 | 执行利率,字符串格式(如 "4.20" |
**响应示例**:
成功 (200):
```json
{
"code": 200,
"msg": "设定成功"
}
```
失败 (404):
```json
{
"code": 404,
"msg": "记录不存在"
}
```
失败 (500):
```json
{
"code": 500,
"msg": "设定失败"
}
```
## 代码设计
### Entity 层
**LoanPricingWorkflow.java**
```java
/** 执行利率(%) */
private String executeRate;
```
### Service 层
**ILoanPricingWorkflowService.java**
```java
/**
* 设定执行利率
* @param serialNum 业务方流水号
* @param executeRate 执行利率
* @return 是否成功
*/
boolean setExecuteRate(String serialNum, String executeRate);
```
**LoanPricingWorkflowServiceImpl.java**
- 实现上述方法
- 根据 `serialNum` 更新记录的 `execute_rate` 字段
- MyBatis Plus 会自动填充 `update_by``update_time`
### Controller 层
**LoanPricingWorkflowController.java**
```java
/**
* 设定执行利率
*/
@Operation(summary = "设定执行利率")
@Log(title = "利率定价流程", businessType = BusinessType.UPDATE)
@PutMapping("/{serialNum}/executeRate")
public AjaxResult setExecuteRate(
@Parameter(description = "业务方流水号")
@PathVariable("serialNum") String serialNum,
@RequestBody Map<String, String> request)
{
String executeRate = request.get("executeRate");
boolean success = loanPricingWorkflowService.setExecuteRate(serialNum, executeRate);
return success ? success() : error("设定失败");
}
```
### VO 层变更
**LoanPricingWorkflowVO.java**
- 添加 `executeRate` 字段到 VO确保详情接口返回执行利率
## 数据校验
1. **记录存在性**: 根据 `serialNum` 查询记录,不存在则返回 404
2. **更新结果检查**: 检查更新操作影响行数0 行表示记录不存在
3. **格式校验**: 执行利率为字符串格式,前端传递格式化后的值(如 "4.20"
## 事务处理
- 使用 MyBatis Plus 的 `updateById` 方法,自动处理事务
- 更新失败时抛出异常,由全局异常处理器处理
## 日志记录
- 使用 `@Log` 注解记录操作日志
- 日志类型: `BusinessType.UPDATE`
- 自动记录操作人和操作时间

View File

@@ -1,63 +0,0 @@
# 提案: 添加执行利率设定接口
## 背景
当前利率定价流程已有测算利率(模型输出计算得到),但缺少最终执行利率的设定功能。业务人员需要根据模型测算结果和实际情况,手动设定最终执行的贷款利率。
## 问题
1. 数据库表中没有存储执行利率的字段
2. 后端缺少设定执行利率的接口
3. API 文档需要更新
## 提案概述
为利率定价流程添加执行利率设定功能,允许业务人员为流程记录设定/更新最终执行利率。
### 功能范围
1. **数据库变更**
-`loan_pricing_workflow` 表中添加 `execute_rate` 字段
2. **后端接口**
- 新增 `PUT /loanPricing/workflow/{serialNum}/executeRate` 接口
- 支持设定和更新执行利率
- 无需特殊权限控制(与查询接口保持一致)
- 可多次修改执行利率
3. **API 文档更新**
-`doc/api/loan-pricing-workflow-api.md` 中添加新接口文档
## 影响范围
- 数据库: `loan_pricing_workflow`
- 后端:
- Entity: `LoanPricingWorkflow.java`
- Service: `ILoanPricingWorkflowService.java` 及实现类
- Controller: `LoanPricingWorkflowController.java`
- 文档: `doc/api/loan-pricing-workflow-api.md`
## 设计考虑
1. **字段类型**: 使用 `varchar(20)` 类型,与 `loan_rate` 保持一致
2. **可空性**: 允许为 NULL未设定时返回 null
3. **可修改性**: 允许多次修改,记录 `update_by``update_time`
4. **权限控制**: 暂不加独立权限,所有登录用户可操作(后续可根据需要添加)
5. **接口语义**: 使用 PUT 语义表示更新资源
## 替代方案
### 方案 A: 添加专门的审批流程(未采纳)
- **优点**: 流程更规范,支持审批
- **缺点**: 实现复杂度高,当前需求不明确
### 方案 B: 在创建接口中直接支持(未采纳)
- **优点**: 减少接口数量
- **缺点**: 业务上执行利率是在查看测算结果后设定的,与创建分离更合理
### 方案 C: 独立的设定接口(采纳)
- **优点**: 职责清晰,实现简单,支持多次修改
- **缺点**: 无明显缺点

View File

@@ -1,27 +0,0 @@
# loan-pricing-workflow Delta
## ADDED Requirements
### Requirement: 执行利率设定
系统 SHALL 提供设定执行利率的接口,允许业务人员为利率定价流程设定或更新最终执行利率。
#### Scenario: 设定执行利率
- **WHEN** 业务人员对已存在的利率定价流程调用设定执行利率接口,提供有效的业务方流水号和执行利率值
- **THEN** 系统更新该流程记录的执行利率字段,返回成功响应,并自动记录更新者和更新时间
#### Scenario: 更新已有执行利率
- **WHEN** 业务人员对已设定执行利率的流程再次调用设定接口
- **THEN** 系统覆盖更新执行利率为新的值
#### Scenario: 设定不存在的流程
- **WHEN** 业务人员提供的业务方流水号不存在
- **THEN** 系统返回"记录不存在"的错误信息
#### Scenario: 执行利率在详情中返回
- **WHEN** 业务人员查询流程详情
- **THEN** 系统在响应数据中包含 `executeRate` 字段(如果已设定则返回值,否则返回 null)

View File

@@ -1,77 +0,0 @@
# 实施任务
## 任务清单
1. **添加数据库字段**
- 文件: 创建 SQL 迁移脚本 `sql/add_execute_rate_field.sql`
- 操作: 在 `loan_pricing_workflow` 表中添加 `execute_rate` 字段
-
DDL: `ALTER TABLE loan_pricing_workflow ADD COLUMN execute_rate varchar(20) DEFAULT NULL COMMENT '执行利率(%)' AFTER loan_rate;`
- 验证: 字段添加成功
2. **更新 Entity 类**
- 文件: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/entity/LoanPricingWorkflow.java`
- 操作: 添加 `executeRate` 字段及注释
- 验证: 字段添加成功,位于 `loanRate` 字段之后
3. **更新 VO 类**
- 文件: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/vo/LoanPricingWorkflowVO.java`
- 操作: 添加 `executeRate` 字段及注释
- 验证: 字段添加成功
4. **更新 Service 接口**
- 文件: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/ILoanPricingWorkflowService.java`
- 操作: 添加 `setExecuteRate(String serialNum, String executeRate)` 方法声明
- 验证: 方法添加成功
5. **实现 Service 方法**
- 文件: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/impl/LoanPricingWorkflowServiceImpl.java`
- 操作: 实现 `setExecuteRate` 方法
- 逻辑: 根据 serialNum 查询记录,更新 execute_rate 字段
- 验证: 方法实现完成
6. **添加 Controller 接口**
- 文件: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/controller/LoanPricingWorkflowController.java`
- 操作: 添加 `PUT /{serialNum}/executeRate` 接口方法
- 验证: 接口添加成功,添加 Swagger 注解
7. **更新 API 文档**
- 文件: `doc/api/loan-pricing-workflow-api.md`
- 操作: 在接口列表中添加"设定执行利率"接口文档
- 内容: 接口地址、请求参数、响应示例、说明
- 验证: 文档更新完整
8. **后端编译验证**
- 操作: 运行 `mvn clean compile` 或 IDE 编译
- 验证: 编译成功无错误
9. **接口功能验证**
- 操作:
- 启动后端服务
- 调用 `PUT /loanPricing/workflow/{serialNum}/executeRate` 接口
- 调用 `GET /loanPricing/workflow/{serialNum}` 接口验证返回值
- 验证:
- 设定执行利率成功
- 再次设定可覆盖更新
- 不存在的 serialNum 返回 404
- 详情接口正确返回 executeRate
## 依赖关系
- 任务 1 必须首先执行(数据库字段)
- 任务 2、3 可并行执行Entity 和 VO
- 任务 4、5 依次执行Service 接口 -> 实现)
- 任务 6 依赖任务 5
- 任务 7 可在任务 6 完成后执行
- 任务 8、9 依次执行
## 验收标准
- [x] 数据库字段 `execute_rate` 添加成功
- [x] Entity 和 VO 类添加 `executeRate` 字段
- [x] Service 接口和实现方法添加成功
- [x] Controller 接口添加成功并编译通过
- [x] API 文档更新完整
- [x] 接口调用成功,执行利率正确保存
- [x] 详情接口正确返回 `executeRate`
- [x] 不存在的记录返回 404

View File

@@ -1,160 +0,0 @@
# 设计文档: 模型输出展示
## 概述
本文档描述在流程详情页面中添加模型输出展示功能的技术设计。
## 页面结构
### 当前布局
```
┌─────────────────────────────────────────────────────────┐
│ 页面标题: 流程详情 [返回按钮] │
├──────────────────────┬──────────────────────────────────┤
│ 关键信息摘要 (30%) │ 详情标签页 (70%) │
│ ┌────────────────┐ │ ┌────────────────────────────┐ │
│ │ 流水号 │ │ │ [基本信息][业务信息]... │ │
│ │ 客户名称 │ │ │ │ │
│ │ 客户类型 │ │ │ 字段内容... │ │
│ │ 申请金额 │ │ │ │ │
│ │ 贷款利率 │ │ │ │ │
│ │ 担保方式 │ │ │ │ │
│ └────────────────┘ │ └────────────────────────────┘ │
└──────────────────────┴──────────────────────────────────┘
```
### 新增布局
```
┌─────────────────────────────────────────────────────────┐
│ 页面标题: 流程详情 [返回按钮] │
├──────────────────────┬──────────────────────────────────┤
│ 关键信息摘要 (30%) │ 详情标签页 (70%) │
│ ┌────────────────┐ │ ┌────────────────────────────┐ │
│ │ 流水号 │ │ │ [基本信息][业务信息]... │ │
│ │ 客户名称 │ │ │ │ │
│ │ 客户类型 │ │ │ 字段内容... │ │
│ │ 申请金额 │ │ │ │ │
│ │ 贷款利率 │ │ │ │ │
│ │ 担保方式 │ │ │ │ │
│ └────────────────┘ │ └────────────────────────────┘ │
├──────────────────────┴──────────────────────────────────┤
│ 模型输出 (当有数据时显示) │
│ ┌────────────────────────────────────────────────────┐│
│ │ [基本信息][忠诚度分析][贡献度分析]... ││
│ │ ││
│ │ 字段内容... ││
│ └────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────┘
```
## 组件设计
### ModelOutputDisplay 组件
建议创建独立的模型输出展示组件,便于维护和复用。
```vue
<template>
<el-card v-if="shouldDisplay" class="model-output-card">
<div slot="header" class="card-header">
<span class="card-title">模型输出</span>
</div>
<el-tabs v-model="activeTab">
<!-- 个人客户 Tabs -->
<template v-if="custType === '个人'">
<el-tab-pane label="基本信息" key="retail-basic">...</el-tab-pane>
<el-tab-pane label="忠诚度分析" key="retail-loyalty">...</el-tab-pane>
<el-tab-pane label="贡献度分析" key="retail-contribution">...</el-tab-pane>
<el-tab-pane label="关联度分析" key="retail-relevance">...</el-tab-pane>
<el-tab-pane label="贷款特征" key="retail-loan">...</el-tab-pane>
<el-tab-pane label="风险度分析" key="retail-risk">...</el-tab-pane>
<el-tab-pane label="测算结果" key="retail-result">...</el-tab-pane>
</template>
<!-- 企业客户 Tabs -->
<template v-else-if="custType === '企业'">
<el-tab-pane label="基本信息" key="corp-basic">...</el-tab-pane>
<el-tab-pane label="忠诚度分析" key="corp-loyalty">...</el-tab-pane>
<el-tab-pane label="贡献度分析" key="corp-contribution">...</el-tab-pane>
<el-tab-pane label="关联度分析" key="corp-relevance">...</el-tab-pane>
<el-tab-pane label="企业类别" key="corp-category">...</el-tab-pane>
<el-tab-pane label="贷款特征" key="corp-loan">...</el-tab-pane>
<el-tab-pane label="风险度分析" key="corp-risk">...</el-tab-pane>
<el-tab-pane label="测算结果" key="corp-result">...</el-tab-pane>
</template>
</el-tabs>
</el-card>
</template>
```
## 数据流
### API 响应结构
```json
{
"code": 200,
"msg": "查询成功",
"data": {
"loanPricingWorkflow": { ... },
"modelRetailOutputFields": { ... }, // 个人客户时存在
"modelCorpOutputFields": { ... } // 企业客户时存在
}
}
```
### 组件 Props
| Prop | 类型 | 说明 |
|------|------|------|
| custType | String | 客户类型(个人/企业) |
| retailOutput | Object | 个人客户模型输出数据 |
| corpOutput | Object | 企业客户模型输出数据 |
## 样式规范
### 卡片样式
与现有 `.summary-card``.detail-card` 保持一致:
- 头部背景色: `#fafafa`
- 边框颜色: `#ebeef5`
- 内边距: 头部 `16px 20px`, 内容 `20px`
- 标题字号: `16px`, 字重 `500`
- 标题颜色: `#303133`
### Tab 样式
使用 Element UI 默认 Tab 样式,间距保持一致。
## 字段映射表
### 个人客户模型输出字段
| Tab | 字段名 | 显示标签 | 格式化 |
|-----|--------|----------|--------|
| 基本信息 | custIsn | 客户内码 | - |
| 基本信息 | custName | 客户名称 | - |
| 基本信息 | idType | 证件类型 | - |
| 基本信息 | idNum | 证件号码 | - |
| 基本信息 | baseLoanRate | 基准利率 | - |
| 测算结果 | totalBp | 浮动BP | - |
| 测算结果 | calculateRate | 测算利率 | 高亮显示 |
### 企业客户模型输出字段
| Tab | 字段名 | 显示标签 | 格式化 |
|-----|--------|----------|--------|
| 基本信息 | custIsn | 客户内码 | - |
| 基本信息 | custName | 客户名称 | - |
| 基本信息 | idType | 证件类型 | - |
| 基本信息 | idNum | 证件号码 | - |
| 基本信息 | baseLoanRate | 基准利率 | - |
| 测算结果 | totalBp | 浮动BP | - |
| 测算结果 | calculateRate | 测算利率 | 高亮显示 |
## 响应式设计
- 桌面端 (≥768px): 模型输出卡片宽度 100%Tab 内容两列布局
- 移动端 (<768px): 模型输出卡片宽度 100%Tab 内容单列布局

View File

@@ -1,74 +0,0 @@
# 提案: 在流程详情页添加模型输出展示
## 背景
利率定价流程详情接口已更新,新增了模型输出字段 (`modelRetailOutputFields``modelCorpOutputFields`)。目前前端详情页面仅展示流程基本信息,未展示模型输出数据。
## 问题
用户在查看流程详情时,无法看到模型计算的输出结果(包括各项 BP 值、测算利率等关键信息),影响业务决策和问题排查。
## 提案概述
在流程详情页面 (`/loanPricing/workflow/detail/:serialNum`) 下方新增独立的模型输出展示区域,根据客户类型(个人/企业)显示对应的模型输出字段。
### 展示逻辑
-`loanPricingWorkflow.custType === "个人"` 时,展示 `modelRetailOutputFields` 字段
-`loanPricingWorkflow.custType === "企业"` 时,展示 `modelCorpOutputFields` 字段
- 当模型输出数据为空时,隐藏该展示区域
### 布局结构
保持与现有页面风格一致,采用卡片 + Tab 标签页的形式展示模型输出字段。
#### 个人客户模型输出 Tab 分类
| Tab 名称 | 字段内容 |
|---------|---------|
| 基本信息 | 客户内码、客户名称、证件类型、证件号码、基准利率 |
| 忠诚度分析 | 我行首贷客户、用信天数、客户年龄、BP_首贷、BP_贷龄、BP_年龄、TOTAL_BP_忠诚度 |
| 贡献度分析 | 存款年日均、贷款年日均、派生率、TOTAL_BP_贡献度 |
| 关联度分析 | 中间业务_个人_信用卡、中间业务_个人_一码通、中间业务_个人_丰收互联、中间业务_个人_有效客户、中间业务_个人_快捷支付、中间业务_个人_电费代扣、中间业务_个人_水费代扣、中间业务_个人_华数费代扣、中间业务_个人_煤气费代扣、中间业务_个人_市民卡、中间业务_个人_理财业务、中间业务_个人_etc、BP_中间业务、TOTAL_BP_关联度 |
| 贷款特征 | 申请金额、BP_贷款额度、贷款用途、是否有经营佐证、BP_贷款用途、循环功能、BP_循环功能、抵质押类型、抵质押物三方所有、BP_抵押物 |
| 风险度分析 | 灰名单客户、本金逾期、利息逾期、信用卡逾期、BP_灰名单与逾期、TOTAL_BP_风险度 |
| 测算结果 | 浮动BP、测算利率 |
#### 企业客户模型输出 Tab 分类
| Tab 名称 | 字段内容 |
|---------|---------|
| 基本信息 | 客户内码、客户名称、证件类型、证件号码、基准利率 |
| 忠诚度分析 | 我行首贷客户、用信天数、BP_首贷、BP_贷龄、TOTAL_BP_忠诚度 |
| 贡献度分析 | 存款年日均、贷款年日均、派生率、TOTAL_BP_贡献度 |
| 关联度分析 | 中间业务_企业_企业互联、中间业务_企业_有效价值客户、中间业务_企业_国际业务、中间业务_企业_承兑、中间业务_企业_贴现、中间业务_企业_电费代扣、中间业务_企业_水费代扣、中间业务_企业_税务代扣、BP_中间业务、代发工资户数、存量贷款余额、BP_代发工资、TOTAL_BP_关联度 |
| 企业类别 | 净身企业、开立基本结算账户、省农担担保贷款、绿色贷款、科技型企业、BP_企业客户类别 |
| 贷款特征 | 贷款期限、BP_贷款期限、申请金额、BP_贷款额度、抵质押类型、抵质押物三方所有、BP_抵押物 |
| 风险度分析 | 灰名单客户、本金逾期、利息逾期、信用卡逾期、BP_灰名单与逾期、TOTAL_BP_风险度 |
| 测算结果 | 浮动BP、测算利率 |
## 影响范围
- 前端: `ruoyi-ui/src/views/loanPricing/workflow/detail.vue`
- API: 使用现有的 `GET /loanPricing/workflow/{serialNum}` 接口
## 设计考虑
1. **独立性**: 模型输出区域与流程基本信息分离,避免页面过于臃肿
2. **一致性**: 采用与现有详情页面相同的卡片 + Tab 布局风格
3. **响应式**: 保持移动端友好布局
4. **可扩展**: 预留未来可能新增的模型输出字段
## 替代方案
### 方案 A: 在现有详情对话框中添加 Tab (未采纳)
- **优点**: 集中展示,减少页面跳转
- **缺点**: 详情页改为独立页面后此方案不适用
### 方案 B: 新增独立页面展示模型输出 (未采纳)
- **优点**: 完全分离,职责清晰
- **缺点**: 增加用户操作步骤,需要额外的路由和菜单配置
### 方案 C: 在详情页下方新增卡片区域 (采纳)
- **优点**: 一次性获取所有信息,用户体验好,实现简单
- **缺点**: 单次页面内容较多(通过 Tab 解决)

View File

@@ -1,63 +0,0 @@
# loan-pricing-workflow-ui Spec Delta
## ADDED Requirements
### Requirement: 流程详情-模型输出展示
系统 SHALL 在流程详情页面中展示模型输出字段,根据客户类型显示对应的个人或企业模型输出数据。
#### Scenario: 查看个人客户模型输出
- **WHEN** 用户在流程详情页面查看个人客户的流程记录,且后端返回了 `modelRetailOutputFields` 数据
- **THEN** 系统在页面下方显示"模型输出"卡片区域,包含 7 个 Tab 标签页:
- **基本信息**: 客户内码、客户名称、证件类型、证件号码、基准利率
- **忠诚度分析**: 我行首贷客户、用信天数、客户年龄、BP_首贷、BP_贷龄、BP_年龄、TOTAL_BP_忠诚度
- **贡献度分析**: 存款年日均、贷款年日均、派生率、TOTAL_BP_贡献度
- **关联度分析**: 中间业务_个人_信用卡、中间业务_个人_一码通、中间业务_个人_丰收互联、中间业务_个人_有效客户、中间业务_个人_快捷支付、中间业务_个人_电费代扣、中间业务_个人_水费代扣、中间业务_个人_华数费代扣、中间业务_个人_煤气费代扣、中间业务_个人_市民卡、中间业务_个人_理财业务、中间业务_个人_etc、BP_中间业务、TOTAL_BP_关联度
- **贷款特征**: 申请金额、BP_贷款额度、贷款用途、是否有经营佐证、BP_贷款用途、循环功能、BP_循环功能、抵质押类型、抵质押物三方所有、BP_抵押物
- **风险度分析**: 灰名单客户、本金逾期、利息逾期、信用卡逾期、BP_灰名单与逾期、TOTAL_BP_风险度
- **测算结果**: 浮动BP、测算利率
#### Scenario: 查看企业客户模型输出
- **WHEN** 用户在流程详情页面查看企业客户的流程记录,且后端返回了 `modelCorpOutputFields` 数据
- **THEN** 系统在页面下方显示"模型输出"卡片区域,包含 8 个 Tab 标签页:
- **基本信息**: 客户内码、客户名称、证件类型、证件号码、基准利率
- **忠诚度分析**: 我行首贷客户、用信天数、BP_首贷、BP_贷龄、TOTAL_BP_忠诚度
- **贡献度分析**: 存款年日均、贷款年日均、派生率、TOTAL_BP_贡献度
- **关联度分析**: 中间业务_企业_企业互联、中间业务_企业_有效价值客户、中间业务_企业_国际业务、中间业务_企业_承兑、中间业务_企业_贴现、中间业务_企业_电费代扣、中间业务_企业_水费代扣、中间业务_企业_税务代扣、BP_中间业务、代发工资户数、存量贷款余额、BP_代发工资、TOTAL_BP_关联度
- **企业类别**: 净身企业、开立基本结算账户、省农担担保贷款、绿色贷款、科技型企业、BP_企业客户类别
- **贷款特征**: 贷款期限、BP_贷款期限、申请金额、BP_贷款额度、抵质押类型、抵质押物三方所有、BP_抵押物
- **风险度分析**: 灰名单客户、本金逾期、利息逾期、信用卡逾期、BP_灰名单与逾期、TOTAL_BP_风险度
- **测算结果**: 浮动BP、测算利率
#### Scenario: 无模型输出数据时隐藏展示区域
- **WHEN** 用户在流程详情页面查看流程记录,但 `modelRetailOutputFields``modelCorpOutputFields` 均为空
- **THEN** 系统不显示"模型输出"卡片区域
#### Scenario: 模型输出字段布尔值格式化
- **WHEN** 模型输出字段中布尔类型值(如 "true"/"false"
- **THEN** 系统将其格式化为中文"是"/"否"显示
#### Scenario: 模型输出字段空值处理
- **WHEN** 模型输出字段值为 null 或空字符串
- **THEN** 系统显示占位符"-"或空,不显示 "null" 或 "undefined"
#### Scenario: 模型输出区域布局一致性
- **WHEN** 用户查看流程详情页面
- **THEN** "模型输出"卡片区域的样式、Tab 样式、字体、间距与上方"流程详情"区域保持一致
#### Scenario: 模型输出区域响应式布局
- **WHEN** 用户在移动设备或小屏幕上查看流程详情页面
- **THEN** "模型输出"卡片区域正常显示Tab 标签页可正常切换,字段描述列表采用单列布局
## MODIFIED Requirements
### Requirement: 流程详情查看
系统 SHALL 提供流程详情查看功能,以独立页面形式展示完整的流程信息,包括模型输出数据。
#### Scenario: 查看流程详情
- **WHEN** 用户在流程列表页面且具有 `loanPricing:workflow:query` 权限,点击列表中某条记录的"查看"按钮
- **THEN** 系统跳转至流程详情页面 `/loanPricing/workflow/detail/:serialNum`,展示:
- **左侧摘要卡片**: 业务方流水号、客户名称、客户类型、申请金额、贷款利率、担保方式
- **右侧详情标签页**: 基本信息页签、业务信息页签、中间业务标识页签、企业标识页签、其他信息页签
- **下方模型输出卡片**: 当存在模型输出数据时显示,根据客户类型展示对应的个人或企业模型输出字段

View File

@@ -1,53 +0,0 @@
# 任务列表: 模型输出展示功能
## 实施顺序
### 1. 前端页面结构调整
- [x] 在 detail.vue 中新增模型输出展示区域el-card
- [x] 添加条件渲染逻辑:仅当模型输出数据存在时显示
- [x] 添加客户类型判断逻辑:个人/企业显示不同字段
- [x] 抽离模型输出组件 ModelOutputDisplay.vue
### 2. 页面布局调整
- [x] 将模型输出组件放在关键信息右侧(三栏布局)
- [x] 调整响应式布局支持不同屏幕尺寸
### 3. 个人客户模型输出组件
- [x] 创建个人模型输出 Tab 结构7 个 Tab
- [x] 实现"基本信息"Tab 字段展示5 个字段)
- [x] 实现"忠诚度分析"Tab 字段展示7 个字段)
- [x] 实现"贡献度分析"Tab 字段展示4 个字段)
- [x] 实现"关联度分析"Tab 字段展示14 个字段)
- [x] 实现"贷款特征"Tab 字段展示10 个字段)
- [x] 实现"风险度分析"Tab 字段展示7 个字段)
- [x] 实现"测算结果"Tab 字段展示2 个字段)
### 4. 企业客户模型输出组件
- [x] 创建企业模型输出 Tab 结构8 个 Tab
- [x] 实现"基本信息"Tab 字段展示5 个字段)
- [x] 实现"忠诚度分析"Tab 字段展示6 个字段)
- [x] 实现"贡献度分析"Tab 字段展示4 个字段)
- [x] 实现"关联度分析"Tab 字段展示13 个字段)
- [x] 实现"企业类别"Tab 字段展示6 个字段)
- [x] 实现"贷款特征"Tab 字段展示7 个字段)
- [x] 实现"风险度分析"Tab 字段展示7 个字段)
- [x] 实现"测算结果"Tab 字段展示2 个字段)
### 5. 数据适配
- [x] 修改 API 响应数据解析逻辑,支持 `LoanPricingWorkflowVO` 结构
- [x] 添加模型输出字段的数据绑定
- [x] 添加布尔值字段的格式化true/false → 是/否)
- [x] 添加空值处理逻辑
### 6. 样式调整
- [x] 保持与现有详情页面一致的卡片样式
- [x] 保持 Tab 样式一致性
- [x] 确保响应式布局在移动端正常显示
- [x] 调整卡片间距
### 7. 测试验证
- [ ] 测试个人客户数据展示
- [ ] 测试企业客户数据展示
- [ ] 测试无模型输出数据时的页面表现
- [ ] 测试响应式布局
- [ ] 测试各 Tab 切换交互

View File

@@ -1,61 +0,0 @@
# 提案: 将模型输出展示组件改为三列布局
## 背景
当前 `ModelOutputDisplay.vue` 组件中所有 `el-descriptions` 使用 `:column="2"` 两列布局展示模型输出字段。
## 问题
两列布局导致垂直空间占用较多,用户需要滚动更多才能查看完整信息。三列布局可以更好地利用屏幕宽度(特别是在桌面端),减少垂直滚动需求。
## 提案概述
`ModelOutputDisplay.vue` 组件中所有 `el-descriptions``:column` 属性从 `2` 修改为 `3`
### 影响范围
- 前端: `ruoyi-ui/src/views/loanPricing/workflow/components/ModelOutputDisplay.vue`
### 具体修改点
需要修改以下位置的 `:column` 属性:
#### 个人客户模型输出
1. 基本信息 (line 11): `:column="2"``:column="3"`
2. 忠诚度分析 (line 22): `:column="2"``:column="3"`
3. 贡献度分析 (line 35): `:column="2"``:column="3"`
4. 关联度分析 (line 45): `:column="2"``:column="3"`
5. 贷款特征 (line 65): `:column="2"``:column="3"`
6. 风险度分析 (line 81): `:column="2"``:column="3"`
7. 测算结果 (line 93): `:column="2"``:column="3"`
#### 企业客户模型输出
8. 基本信息 (line 104): `:column="2"``:column="3"`
9. 忠诚度分析 (line 115): `:column="2"``:column="3"`
10. 贡献度分析 (line 126): `:column="2"``:column="3"`
11. 关联度分析 (line 136): `:column="2"``:column="3"`
12. 企业类别 (line 155): `:column="2"``:column="3"`
13. 贷款特征 (line 167): `:column="2"``:column="3"`
14. 风险度分析 (line 180): `:column="2"``:column="3"`
15. 测算结果 (line 192): `:column="2"``:column="3"`
## 设计考虑
1. **空间利用**: 三列布局可以减少约 33% 的垂直空间占用
2. **可读性**: Element UI 的 `el-descriptions` 组件会自动调整标签宽度三列布局在标准桌面显示器1920px 宽度)下可读性良好
3. **兼容性**: `el-descriptions` 组件原生支持多列布局,无需额外样式调整
4. **响应式**: 在小屏幕设备上Element UI 会自动调整布局,无需额外处理
## 替代方案
### 方案 A: 保持两列布局 (未采纳)
- **优点**: 标签内容空间更充足
- **缺点**: 垂直空间占用大,需要更多滚动
### 方案 B: 使用四列布局 (未采纳)
- **优点**: 垂直空间占用最少
- **缺点**: 标签内容可能被压缩,影响可读性
### 方案 C: 改为三列布局 (采纳)
- **优点**: 平衡空间利用率和可读性
- **缺点**: 无明显缺点

View File

@@ -1,15 +0,0 @@
# loan-pricing-workflow-ui Delta
## MODIFIED Requirements
### Requirement: 模型输出展示布局
模型输出组件 SHALL 使用三列布局展示字段信息,以提高空间利用率。
#### Scenario: 查看个人客户模型输出三列布局
- **WHEN** 用户在流程详情页查看个人客户记录的模型输出信息
- **THEN** 系统在所有模型输出 Tab基本信息、忠诚度分析、贡献度分析、关联度分析、贷款特征、风险度分析、测算结果中使用三列布局展示字段
#### Scenario: 查看企业客户模型输出三列布局
- **WHEN** 用户在流程详情页查看企业客户记录的模型输出信息
- **THEN** 系统在所有模型输出 Tab基本信息、忠诚度分析、贡献度分析、关联度分析、企业类别、贷款特征、风险度分析、测算结果中使用三列布局展示字段

View File

@@ -1,36 +0,0 @@
# 实施任务
## 任务清单
1. **修改 ModelOutputDisplay.vue 组件列数配置**
- 文件: `ruoyi-ui/src/views/loanPricing/workflow/components/ModelOutputDisplay.vue`
- 操作: 将所有 `el-descriptions``:column="2"` 修改为 `:column="3"`
- 涉及行数: 11, 22, 35, 45, 65, 81, 93, 104, 115, 126, 136, 155, 167, 180, 192
- 验证: 确认所有 15 处 `el-descriptions``:column` 属性已修改为 `3`
2. **前端构建验证**
- 操作: 运行 `cd ruoyi-ui && npm run build:prod`
- 验证: 构建成功无错误
3. **功能验证**
- 操作:
- 启动前端开发服务器 `npm run dev`
- 访问流程详情页,选择个人客户记录,验证模型输出显示为三列
- 选择企业客户记录,验证模型输出显示为三列
- 验证:
- 个人客户所有 7 个 Tab 的字段展示均为三列布局
- 企业客户所有 8 个 Tab 的字段展示均为三列布局
- 标签和值内容正常显示,无溢出或错位
## 依赖关系
- 任务 1 必须首先完成
- 任务 2 和任务 3 可并行执行
## 验收标准
- [x] 所有 `el-descriptions``:column` 属性值均为 `3`
- [x] 前端构建成功
- [x] 个人客户模型输出所有 Tab 正确显示为三列
- [x] 企业客户模型输出所有 Tab 正确显示为三列
- [x] 字段标签和内容显示正常,无布局问题

View File

@@ -1,33 +0,0 @@
# Change: 添加利率定价流程创建功能
## Why
当前 `add-loan-pricing-frontend` 变更已实现流程列表查询和详情查看功能,但缺少创建新流程的能力。业务人员需要能够通过 Web 界面发起新的利率定价申请,而不是直接调用后端 API。
## What Changes
- 修改前端页面组件 `ruoyi-ui/src/views/loanPricing/workflow/index.vue`
- 添加"新增"按钮(带权限控制 `loanPricing:workflow:create`
- 添加创建流程表单对话框
- 实现表单验证逻辑
- 实现表单提交功能
- 新增前端 API 接口函数:
- `createWorkflow(data)` - 创建利率定价流程
- 新增数据库菜单权限:
- 添加创建权限 `loanPricing:workflow:create`
## Impact
- **Affected specs:** 修改 `loan-pricing-workflow-ui` 能力规格
- **Affected code:**
- **修改 `ruoyi-ui/src/api/loanPricing/workflow.js`** - 新增创建接口
- **修改 `ruoyi-ui/src/views/loanPricing/workflow/index.vue`** - 添加创建功能
- **修改 `sys_menu` 表** - 添加创建权限按钮
## Dependencies
- 依赖已完成的 `add-loan-pricing-workflow` 后端变更(提供创建 API
- 依赖已完成的 `add-loan-pricing-frontend` 前端变更(提供列表和详情页面)
- 后端 API 接口文档位于 `doc/api/loan-pricing-workflow-api.md`接口1发起利率定价流程

View File

@@ -1,94 +0,0 @@
# Capability: loan-pricing-workflow-ui
利率定价流程前端用户界面能力。
## MODIFIED Requirements
### Requirement: 流程列表查询
系统 SHALL 提供利率定价流程列表查询页面,支持分页和多条件筛选,并支持创建新流程。
#### Scenario: 查询流程列表
- **WHEN** 用户已登录系统且具有 `loanPricing:workflow:list` 权限,访问"利率定价管理 > 流程列表"菜单
- **THEN** 系统显示利率定价流程列表页面,包含查询表单(客户名称模糊查询、创建者、机构号筛选)、搜索和重置按钮、新增按钮(带权限控制)、数据表格(业务方流水号、客户名称、客户类型、担保方式、申请金额、贷款利率、创建时间、创建者)、分页组件、操作列(包含"查看"按钮)
#### Scenario: 使用筛选条件查询
- **WHEN** 用户在流程列表页面输入客户名称或选择创建者/机构号,点击搜索按钮
- **THEN** 系统根据筛选条件查询并更新列表数据
#### Scenario: 重置筛选条件
- **WHEN** 用户已设置筛选条件,点击重置按钮
- **THEN** 系统清空所有筛选条件并重新查询全部数据
### Requirement: 流程详情查看
系统 SHALL 提供流程详情查看功能,以对话框形式展示完整的流程信息。
#### Scenario: 查看流程详情
- **WHEN** 用户在流程列表页面且具有 `loanPricing:workflow:query` 权限,点击列表中某条记录的"查看"按钮
- **THEN** 系统弹出详情对话框,展示完整的流程信息(基本信息:业务方流水号、机构编码、客户内码、客户名称、证件类型;业务信息:客户类型、担保方式、申请金额、贷款利率、贷款用途;业务标识:中间业务标识、企业标识;抵质押信息:抵质押类型、是否三方所有;其他信息:创建时间、创建者、更新时间、更新者)
### Requirement: 菜单和权限配置
系统 SHALL 在数据库中正确配置菜单项和权限,确保用户可以访问功能。
#### Scenario: 菜单显示和导航
- **WHEN** 用户已登录系统且具有利率定价流程相关权限
- **THEN** 系统在左侧菜单栏显示"利率定价管理"一级菜单,展开后显示"流程列表"二级菜单项
#### Scenario: 菜单路由配置
- **WHEN** 用户点击"流程列表"菜单项,系统处理路由跳转
- **THEN** 系统导航至 `/loanPricing/workflow` 路径,加载对应的前端组件
### Requirement: API 接口集成
前端 SHALL 正确调用后端 API 接口获取数据和提交创建请求。
#### Scenario: 列表接口调用
- **WHEN** 用户访问流程列表页面,页面初始化或用户执行查询操作
- **THEN** 前端调用 `GET /loanPricing/workflow/list` 接口,传入分页和筛选参数
#### Scenario: 详情接口调用
- **WHEN** 用户点击查看按钮,前端获取选中记录的业务方流水号
- **THEN** 前端调用 `GET /loanPricing/workflow/{serialNum}` 接口获取详情数据
#### Scenario: 创建接口调用
- **WHEN** 用户填写完创建表单并点击确定按钮
- **THEN** 前端调用 `POST /loanPricing/workflow/create` 接口,传入表单数据,成功后关闭对话框并刷新列表
## ADDED Requirements
### Requirement: 流程创建
系统 SHALL 提供创建新利率定价流程的功能,通过表单对话框收集必要信息。
#### Scenario: 打开创建表单
- **WHEN** 用户在流程列表页面且具有 `loanPricing:workflow:create` 权限,点击"新增"按钮
- **THEN** 系统弹出创建流程表单对话框,显示所有必填和可选字段
#### Scenario: 表单字段显示
- **WHEN** 用户打开创建流程表单对话框
- **THEN** 系统显示以下字段分组:
- 基本信息:客户内码(必填)、客户名称、客户类型(必填,下拉选择:个人/企业)、证件类型
- 贷款信息:申请金额(必填)、贷款利率(必填)、担保方式(必填,下拉选择:信用/保证/抵押/质押、贷款用途下拉选择consumer/business
- 中间业务标识(个人):个人快捷支付(开关)、个人电费代扣(开关)
- 中间业务标识(企业):企业电费代扣(开关)、企业水费代扣(开关)
- 企业标识净身企业开关、开立基本结算账户开关、制造业企业开关、省农担担保贷款开关、纳税信用等级A级开关、县级及以上农业龙头企业开关、普惠小微借款人开关
- 抵质押信息:抵质押类型(下拉选择:一线/一类/二类)、抵质押物三方所有(开关)、是否有经营佐证(开关)
- 固定字段机构编码隐藏固定值931000、运行模式隐藏固定值1
#### Scenario: 表单验证
- **WHEN** 用户填写表单并点击确定按钮
- **THEN** 系统验证必填字段:客户内码、客户类型、担保方式、申请金额、贷款利率,如有缺失则显示错误提示
#### Scenario: 提交创建成功
- **WHEN** 用户填写完必填字段并点击确定按钮,后端返回成功响应
- **THEN** 系统关闭对话框,显示成功提示消息,刷新列表数据
#### Scenario: 取消创建
- **WHEN** 用户点击取消按钮或对话框关闭按钮
- **THEN** 系统关闭对话框,不保存数据,不刷新列表
#### Scenario: 新增按钮权限控制
- **WHEN** 用户不具有 `loanPricing:workflow:create` 权限
- **THEN** 系统不显示"新增"按钮

View File

@@ -1,39 +0,0 @@
# Tasks: 添加利率定价流程创建功能
## Implementation Tasks
### 1. 新增前端 API 接口
- [x]`ruoyi-ui/src/api/loanPricing/workflow.js` 中添加 `createWorkflow(data)` 函数
- [x] 函数调用 `POST /loanPricing/workflow/create` 接口
### 2. 修改前端页面组件
- [x] 在页面工具栏区域添加"新增"按钮
- [x] 按钮配置权限控制 `v-hasPermi="['loanPricing:workflow:create']"`
- [x] 添加创建流程表单对话框组件
- [x] 实现表单字段(参照 API 文档接口1的请求参数
- 必填字段:机构编码(固定931000)、运行模式(固定1)、客户内码、客户类型、担保方式、申请金额、贷款利率
- 可选字段:客户名称、证件类型、贷款用途
- 业务标识字段:中间业务标识(个人快捷支付、个人电费代扣、企业电费代扣、企业水费代扣)
- 企业标识字段净身企业、开立基本结算账户、制造业企业、省农担担保贷款、纳税信用等级A级、县级及以上农业龙头企业、普惠小微借款人
- 抵质押信息字段:抵质押类型、抵质押物三方所有、是否有经营佐证
- [x] 实现表单验证规则
- [x] 实现 `handleAdd` 方法(打开对话框)
- [x] 实现 `submitForm` 方法(提交表单)
- [x] 实现 `cancelCreate` 方法(取消/关闭对话框)
- [x] 实现 `reset` 方法(重置表单)
### 3. 配置数据库菜单权限
- [x] 准备 SQL 插入语句,在 `sys_menu` 表中添加创建按钮权限:
- menu_id: 2003, menu_name: 流程创建, parent_id: 2001
- perms: `loanPricing:workflow:create`
- [x] 执行 SQL 插入语句
- [x] 关联管理员角色到新菜单权限
### 4. 验证和测试
- [x] 代码实现完成,等待用户启动前端服务进行测试
- [ ] 启动前端开发服务器
- [ ] 验证"新增"按钮是否显示
- [ ] 测试打开创建表单对话框
- [ ] 测试表单验证功能
- [ ] 测试提交创建成功后刷新列表
- [ ] 测试取消和关闭对话框功能

View File

@@ -1,25 +0,0 @@
# Change: 添加利率定价流程前端管理界面
## Why
后端利率定价流程 API 已实现(参见 `add-loan-pricing-workflow` 变更),但缺少对应的前端管理界面。业务人员需要通过 Web 界面查询利率定价流程列表、查看流程详情,而不能直接调用后端 API。
## What Changes
- 新增前端 API 接口模块 `ruoyi-ui/src/api/loanPricing/workflow.js`
- 新增前端页面组件 `ruoyi-ui/src/views/loanPricing/workflow/index.vue`
- 在数据库 `sys_menu` 表中配置菜单项,确保页面可以正常访问
- 配置路由和权限,使用户可以通过菜单导航访问功能
## Impact
- **Affected specs:** 新增 `loan-pricing-workflow-ui` 能力规格
- **Affected code:**
- **新增 `ruoyi-ui/src/api/loanPricing/workflow.js`** - API 接口定义
- **新增 `ruoyi-ui/src/views/loanPricing/workflow/index.vue`** - 列表和详情页面组件
- **修改 `sys_menu` 表** - 添加菜单配置数据
## Dependencies
- 依赖已完成的 `add-loan-pricing-workflow` 后端变更
- 后端 API 接口文档位于 `doc/api/loan-pricing-workflow-api.md`

View File

@@ -1,53 +0,0 @@
# Capability: loan-pricing-workflow-ui
利率定价流程前端用户界面能力。
## ADDED Requirements
### Requirement: 流程列表查询
系统 SHALL 提供利率定价流程列表查询页面,支持分页和多条件筛选。
#### Scenario: 查询流程列表
- **WHEN** 用户已登录系统且具有 `loanPricing:workflow:list` 权限,访问"利率定价管理 > 流程列表"菜单
- **THEN** 系统显示利率定价流程列表页面,包含查询表单(客户名称模糊查询、创建者、机构号筛选)、搜索和重置按钮、数据表格(业务方流水号、客户名称、客户类型、担保方式、申请金额、贷款利率、创建时间、创建者)、分页组件、操作列(包含"查看"按钮)
#### Scenario: 使用筛选条件查询
- **WHEN** 用户在流程列表页面输入客户名称或选择创建者/机构号,点击搜索按钮
- **THEN** 系统根据筛选条件查询并更新列表数据
#### Scenario: 重置筛选条件
- **WHEN** 用户已设置筛选条件,点击重置按钮
- **THEN** 系统清空所有筛选条件并重新查询全部数据
### Requirement: 流程详情查看
系统 SHALL 提供流程详情查看功能,以对话框形式展示完整的流程信息。
#### Scenario: 查看流程详情
- **WHEN** 用户在流程列表页面且具有 `loanPricing:workflow:query` 权限,点击列表中某条记录的"查看"按钮
- **THEN** 系统弹出详情对话框,展示完整的流程信息(基本信息:业务方流水号、机构编码、客户内码、客户名称、证件类型;业务信息:客户类型、担保方式、申请金额、贷款利率、贷款用途;业务标识:中间业务标识、企业标识;抵质押信息:抵质押类型、是否三方所有;其他信息:创建时间、创建者、更新时间、更新者)
### Requirement: 菜单和权限配置
系统 SHALL 在数据库中正确配置菜单项和权限,确保用户可以访问功能。
#### Scenario: 菜单显示和导航
- **WHEN** 用户已登录系统且具有利率定价流程相关权限
- **THEN** 系统在左侧菜单栏显示"利率定价管理"一级菜单,展开后显示"流程列表"二级菜单项
#### Scenario: 菜单路由配置
- **WHEN** 用户点击"流程列表"菜单项,系统处理路由跳转
- **THEN** 系统导航至 `/loanPricing/workflow` 路径,加载对应的前端组件
### Requirement: API 接口集成
前端 SHALL 正确调用后端 API 接口获取数据。
#### Scenario: 列表接口调用
- **WHEN** 用户访问流程列表页面,页面初始化或用户执行查询操作
- **THEN** 前端调用 `GET /loanPricing/workflow/list` 接口,传入分页和筛选参数
#### Scenario: 详情接口调用
- **WHEN** 用户点击查看按钮,前端获取选中记录的业务方流水号
- **THEN** 前端调用 `GET /loanPricing/workflow/{serialNum}` 接口获取详情数据

View File

@@ -1,41 +0,0 @@
# Tasks: 添加利率定价流程前端管理界面
## Implementation Tasks
### 1. 创建前端 API 接口模块
- [x] 创建 `ruoyi-ui/src/api/loanPricing/` 目录
- [x] 创建 `workflow.js` 文件,实现以下 API 函数:
- `listWorkflow(query)` - 查询利率定价流程列表
- `getWorkflow(serialNum)` - 根据业务方流水号查询详情
### 2. 创建前端页面组件
- [x] 创建 `ruoyi-ui/src/views/loanPricing/workflow/` 目录
- [x] 创建 `index.vue` 页面组件,包含:
- 查询表单区域(支持客户名称、创建者、机构号筛选)
- 数据表格区域(显示流程列表)
- 分页组件
- 详情对话框(点击查看按钮弹出)
- [x] 实现以下功能:
- 页面加载时自动查询列表
- 搜索和重置功能
- 点击"查看"按钮弹出详情对话框
- 详情对话框展示完整的流程信息
### 3. 配置数据库菜单
- [x] 准备 SQL 插入语句,在 `sys_menu` 表中添加菜单项:
- 一级菜单利率定价管理menu_type='M'
- 二级菜单流程列表menu_type='C',对应前端组件路径)
- [x] 设置正确的权限标识perms字段
- 列表查询权限:`loanPricing:workflow:list`
- 详情查询权限:`loanPricing:workflow:query`
- [x] 执行 SQL 插入语句
- [x] 关联管理员角色到新菜单
### 4. 验证和测试
- [x] 配置完成,等待用户启动前端服务进行测试
- [ ] 启动前端开发服务器(`npm run dev`
- [ ] 使用 admin 账号登录系统
- [ ] 验证菜单是否正常显示
- [ ] 测试列表查询功能
- [ ] 测试搜索筛选功能
- [ ] 测试详情查看功能

View File

@@ -1,24 +0,0 @@
# Change: 添加利率定价流程管理功能
## Why
当前系统缺少利率定价流程的管理能力。业务人员需要能够发起利率定价申请、查询历史定价记录、查看定价详情。这是贷款定价系统的核心功能需求。
## What Changes
- 创建新的 Maven 模块 `ruoyi-loan-pricing` 用于利率定价相关功能
- 新增利率定价流程的发起接口
- 新增利率定价流程的列表查询接口(支持分页和多条件筛选)
- 新增根据业务方流水号查看详情的接口
- 创建数据库表存储利率定价流程数据
- 添加对应的实体类、Mapper、Service、Controller
## Impact
- **Affected specs:** 新增 `loan-pricing-workflow` 能力规格
- **Affected code:**
- **新增 `ruoyi-loan-pricing` Maven 模块** - 包含 Domain、Mapper、Service
- 修改 `pom.xml` 添加新模块依赖
- 新增 `ruoyi-admin` 模块下的 Controller
- 新增数据库表和 MyBatis XML 映射文件
- 新增前端 API 接口定义和页面组件(待后续阶段实现)

View File

@@ -1,73 +0,0 @@
## ADDED Requirements
### Requirement: 利率定价流程发起
系统 SHALL 提供利率定价流程发起接口,允许业务人员创建新的利率定价申请。
#### Scenario: 成功发起利率定价流程
- **WHEN** 业务人员提交包含必填字段(custIsn、custType、guarType、applyAmt、loanRate)的完整申请
- **THEN** 系统自动生成业务方流水号(serialNum)并保存记录,返回成功响应
#### Scenario: 自动生成业务方流水号
- **WHEN** 发起利率定价流程时
- **THEN** 系统使用时间戳自动生成唯一的业务方流水号,无需用户输入
#### Scenario: 记录创建和更新信息
- **WHEN** 利率定价流程创建成功
- **THEN** 系统自动记录创建者、创建时间、更新者、更新时间
#### Scenario: 字段验证-必填字段
- **WHEN** 提交的申请缺少必填字段(custIsn、custType、guarType、applyAmt、loanRate)
- **THEN** 系统返回参数验证失败的错误信息
#### Scenario: 字段验证-固定值字段
- **WHEN** 提交的申请中 orgCode 非 "931000" 或 runType 非 "1"
- **THEN** 系统返回参数验证失败的错误信息
#### Scenario: 字段验证-枚举值
- **WHEN** 提交的申请中 custType 不是"个人"或"企业"
- **THEN** 系统返回参数验证失败的错误信息
#### Scenario: 字段验证-担保方式
- **WHEN** 提交的申请中 guarType 不是"信用"、"保证"、"抵押"、"质押"之一
- **THEN** 系统返回参数验证失败的错误信息
### Requirement: 利率定价流程列表查询
系统 SHALL 提供利率定价流程列表查询接口,支持分页和多条件筛选。
#### Scenario: 默认按更新时间倒序排列
- **WHEN** 业务人员查询利率定价流程列表
- **THEN** 结果按更新时间(update_time)倒序排列
#### Scenario: 支持分页查询
- **WHEN** 业务人员指定页码和每页数量查询列表
- **THEN** 系统返回对应页的数据及总记录数
#### Scenario: 按创建者筛选
- **WHEN** 业务人员按创建者筛选查询
- **THEN** 系统返回该创建者创建的利率定价流程记录
#### Scenario: 按客户名称筛选
- **WHEN** 业务人员按客户名称(custName)模糊查询
- **THEN** 系统返回客户名称包含查询条件的记录
#### Scenario: 按机构号筛选
- **WHEN** 业务人员按机构号(orgCode)筛选查询
- **THEN** 系统返回该机构号的利率定价流程记录
#### Scenario: 组合条件筛选
- **WHEN** 业务人员同时指定多个筛选条件
- **THEN** 系统返回同时满足所有条件的记录
### Requirement: 利率定价流程详情查询
系统 SHALL 提供根据业务方流水号查询流程详情的接口。
#### Scenario: 根据业务方流水号查询详情
- **WHEN** 业务人员提供有效的业务方流水号(serialNum)
- **THEN** 系统返回该流程的所有字段信息
#### Scenario: 查询不存在的流水号
- **WHEN** 业务人员查询的业务方流水号不存在
- **THEN** 系统返回"记录不存在"的错误信息

View File

@@ -1,78 +0,0 @@
## 1. 创建新 Maven 模块
- [x] 1.1 创建 `ruoyi-loan-pricing` 模块目录结构
- [x] 1.2 创建 `ruoyi-loan-pricing/pom.xml`
- 继承父 pom
- 添加 `ruoyi-common` 依赖
- 添加 MyBatis Plus 依赖
- 添加 Spring Boot 相关依赖
- [x] 1.3 修改根 `pom.xml`
-`<modules>` 中添加 `ruoyi-loan-pricing` 模块
-`dependencyManagement` 中添加模块依赖管理
- [x] 1.4 修改 `ruoyi-admin/pom.xml`
- 添加 `ruoyi-loan-pricing` 模块依赖
## 2. 数据库设计与实现
- [x] 2.1 设计利率定价流程数据库表结构
- 包含所有必需字段(24个字段)
- 添加主键、索引
- 添加审计字段(create_by, create_time, update_by, update_time)
- [x] 2.2 创建数据库表 SQL 脚本
## 3. 后端实体类开发
- [x] 3.1 在 `ruoyi-loan-pricing` 模块中创建 `LoanPricingWorkflow` 实体类
- 使用 `@Data` 注解
- 使用 `@TableName` 映射数据库表名
- 所有字段添加数据库映射注解
- 手动添加审计字段(createBy, createTime, updateBy, updateTime)
- [x] 3.2 添加字段验证注解(@NotNull@NotBlank等)
## 4. 后端 Mapper 层开发
- [x] 4.1 在 `ruoyi-loan-pricing` 模块中创建 `LoanPricingWorkflowMapper` 接口
- 继承 MyBatis Plus 的 `BaseMapper<LoanPricingWorkflow>`
- 定义自定义查询方法(如果需要)
- [x] 4.2 创建 MyBatis XML 映射文件(如果需要自定义 SQL)
## 5. 后端 Service 层开发
- [x] 5.1 在 `ruoyi-loan-pricing` 模块中创建 `ILoanPricingWorkflowService` 接口
- 定义发起流程方法 `createLoanPricing`
- 定义列表查询方法 `selectLoanPricingList`
- 定义详情查询方法 `selectLoanPricingBySerialNum`
- [x] 5.2 创建 `LoanPricingWorkflowServiceImpl` 实现类
- 实现业务逻辑
- 生成业务方流水号(时间戳)
- 实现分页查询
- 实现多条件筛选
## 6. 后端 Controller 层开发
- [x] 6.1 在 `ruoyi-admin` 模块中创建 `LoanPricingWorkflowController` 控制器
- 添加 `@RestController``@RequestMapping` 注解
- 添加 SpringDoc/OpenAPI 注解用于生成 API 文档
- 实现发起接口 `POST /loanPricing/workflow/create`
- 实现列表查询接口 `GET /loanPricing/workflow/list`
- 实现详情查询接口 `GET /loanPricing/workflow/{serialNum}`
- [x] 6.2 添加操作日志注解 `@Log`
- [x] 6.3 添加 SpringDoc 注解生成 API 文档
- 使用 `@Tag` 定义控制器标签
- 使用 `@Operation` 定义接口描述
- 使用 `@Parameter` 定义参数说明
## 7. 测试与验证
- [x] 7.1 编写单元测试(可选)
- [x] 7.2 使用 Postman 或 Swagger UI 进行接口测试
- [x] 7.3 验证所有场景(成功和失败场景)
## 8. 文档与配置
- [x] 8.1 确认 MyBatis Plus 配置正确
- [x] 8.2 确认数据库表已创建
- [x] 8.3 验证 API 文档自动生成
- 访问 `/swagger-ui.html` 确认接口文档已生成
- 验证接口描述、参数说明、响应示例完整
- [x] 8.4 创建 API 接口文档 Markdown 文件

View File

@@ -1,142 +0,0 @@
# 设计文档:流程详情页面
## 架构概述
将流程详情从对话框组件迁移到独立的页面组件,遵循若依框架现有的路由模式。
## 组件设计
### 详情页面组件 (detail.vue)
**位置**`ruoyi-ui/src/views/loanPricing/workflow/detail.vue`
**页面结构**
```
<template>
<div class="app-container">
<!-- 页面标题和操作栏 -->
<el-page-header @back="goBack" :content="pageTitle" />
<!-- 详情内容卡片 -->
<el-card class="mt-20">
<el-descriptions :column="2" border>
<!-- 基本信息 -->
<!-- 业务信息 -->
<!-- 业务标识 -->
<!-- 抵质押信息 -->
<!-- 其他信息 -->
</el-descriptions>
</el-card>
<!-- 返回按钮 -->
<el-row class="mt-20">
<el-col :span="24">
<el-button @click="goBack">返回</el-button>
</el-col>
</el-row>
</div>
</template>
```
**数据获取**
- 通过 `$route.params.serialNum` 获取业务方流水号
-`created()` 钩子中调用 API 获取详情数据
- 处理加载状态和错误状态
**导航逻辑**
- 返回按钮:`this.$router.go(-1)` 或跳转到列表页
- 面包屑导航:高亮"流程列表"菜单项
### 路由配置
**位置**`ruoyi-ui/src/router/index.js` - `dynamicRoutes` 数组
**配置模式**:参考现有的 `/system/user-auth/role/:userId` 路由
```javascript
{
path: '/loanPricing/workflow-detail',
component: Layout,
hidden: true,
permissions: ['loanPricing:workflow:query'],
children: [
{
path: ':serialNum',
component: () => import('@/views/loanPricing/workflow/detail'),
name: 'LoanPricingWorkflowDetail',
meta: { title: '流程详情', activeMenu: '/loanPricing/workflow' }
}
]
}
```
**路由参数说明**
- `:serialNum`:业务方流水号,用于 API 调用
- `activeMenu`:保持列表页菜单高亮
- `permissions`:复用现有权限 `loanPricing:workflow:query`
### 列表页修改
**修改位置**`ruoyi-ui/src/views/loanPricing/workflow/index.vue`
**变更内容**
1. 移除 `openDetail` 状态变量
2. 移除 `handleView()` 方法中的弹窗逻辑
3. 修改"查看"按钮的点击事件,从 `@click="handleView(scope.row)"` 改为路由跳转
**新的 `handleView()` 方法**
```javascript
handleView(row) {
this.$router.push({
name: 'LoanPricingWorkflowDetail',
params: { serialNum: row.serialNum }
})
}
```
**移除内容**
- 详情对话框模板(`<el-dialog title="利率定价流程详情"...>`
- `detail` 数据对象
- `openDetail` 状态
## UI/UX 设计
### 详情页面布局
1. **页面标题**:使用 `el-page-header` 组件,显示"流程详情"标题和返回按钮
2. **内容区域**:使用 `el-card` + `el-descriptions` 展示详情信息,保持与弹窗相同的两列布局
3. **底部操作**:返回按钮(也可以考虑移除,因为有页面标题的返回按钮)
### 响应式设计
- 移动端:`el-descriptions` 自动调整为单列
- 内容区域添加适当的内边距和外边距
### 加载状态
- 显示 loading 遮罩层,直到数据加载完成
- 处理 API 错误,显示错误提示并返回列表页
## 技术约束
1. **框架版本**Vue Router 3.4.9
2. **路由模式**History 模式(去掉 URL 中的 #
3. **权限控制**:通过 `permissions` 字段控制路由访问
4. **组件懒加载**:使用 `() => import()` 动态导入
## 测试策略
### 单元测试
- 路由跳转逻辑
- 参数解析
- API 调用
### 集成测试
- 从列表页跳转到详情页
- 详情页返回到列表页
- 权限控制(无权限用户无法访问)
### UI 测试
- 详情信息正确显示
- 面包屑导航正确高亮
- 返回按钮正常工作

View File

@@ -1,67 +0,0 @@
# 提案:将流程详情查看功能从弹窗改为独立页面
## 概述
将流程列表中的"查看流程"按钮功能从弹窗展示改为跳转到单独的页面展示。
## 动机
当前流程详情通过对话框Dialog展示存在以下问题
- 详情信息较多20+字段),在弹窗中展示需要滚动,用户体验不佳
- 弹窗宽度固定800px长字段显示受限
- 无法通过 URL 直接分享或访问特定流程的详情页
- 不利于后续扩展(如添加编辑、审批等操作)
## 目标
1. 创建独立的流程详情页面组件
2. 修改列表页的"查看"按钮,从弹窗改为路由跳转
3. 在动态路由中配置详情页路由
4. 保持现有的 API 接口调用不变
## 影响范围
### 前端文件
- 修改:[ruoyi-ui/src/views/loanPricing/workflow/index.vue](ruoyi-ui/src/views/loanPricing/workflow/index.vue) - 移除详情对话框,修改查看按钮逻辑
- 新增:[ruoyi-ui/src/views/loanPricing/workflow/detail.vue](ruoyi-ui/src/views/loanPricing/workflow/detail.vue) - 新的详情页面组件
- 修改:[ruoyi-ui/src/router/index.js](ruoyi-ui/src/router/index.js) - 添加详情页动态路由
### 后端文件
- 无需修改API 接口保持不变
## 相关规格
此变更将修改以下规格:
- [loan-pricing-workflow-ui](../specs/loan-pricing-workflow-ui/spec.md) - 流程详情查看需求的实现方式变更
## 备选方案
### 方案 A当前方案独立页面
- 优点:更好的用户体验,可扩展性强,支持 URL 分享
- 缺点:需要创建新组件和路由配置
### 方案 B保留弹窗优化展示
- 优点:改动较小
- 缺点:仍然受限于弹窗尺寸,用户体验改善有限
### 方案 C抽屉Drawer式侧边栏
- 优点:利用垂直空间,可以展示更多信息
- 缺点:在移动端体验不佳
**选择方案 A**,因为它提供了最佳的用户体验和扩展性。
## 风险与缓解
| 风险 | 影响 | 缓解措施 |
|------|------|----------|
| 路由配置错误导致 404 | 高 | 严格遵循现有路由模式,进行充分测试 |
| 详情页返回逻辑问题 | 中 | 添加面包屑导航和返回按钮 |
| 样式不一致 | 低 | 复用现有组件和样式 |
## 时间表
此变更预计在批准后立即实施,包含以下步骤:
1. 创建详情页面组件
2. 修改列表页查看逻辑
3. 配置路由
4. 测试验证

View File

@@ -1,29 +0,0 @@
# loan-pricing-workflow-ui 规格变更
此规格定义了利率定价流程管理的前端用户界面需求。
## MODIFIED Requirements
### Requirement: 流程详情查看
系统 SHALL 提供流程详情查看功能,以独立页面的形式展示完整的流程信息。
#### Scenario: 查看流程详情
- **WHEN** 用户在流程列表页面且具有 `loanPricing:workflow:query` 权限,点击列表中某条记录的"查看"按钮
- **THEN** 系统跳转至独立的流程详情页面,路径为 `/loanPricing/workflow-detail/{serialNum}`,展示完整的流程信息(基本信息:业务方流水号、机构编码、客户内码、客户名称、证件类型;业务信息:客户类型、担保方式、申请金额、贷款利率、贷款用途;业务标识:中间业务标识、企业标识;抵质押信息:抵质押类型、是否三方所有;其他信息:创建时间、创建者、更新时间、更新者)
#### Scenario: 详情页面导航
- **WHEN** 用户在流程详情页面
- **THEN** 系统显示页面标题"流程详情"、返回按钮,面包屑导航高亮"利率定价管理 > 流程列表",点击返回按钮可返回流程列表页面
#### Scenario: 详情页面路由配置
- **WHEN** 系统初始化加载路由配置
- **THEN** 系统在动态路由中注册详情页路由,组件路径为 `@/views/loanPricing/workflow/detail`,路由参数 `serialNum` 用于标识具体流程,访问权限为 `loanPricing:workflow:query`
#### Scenario: URL 直接访问详情页
- **WHEN** 用户直接在浏览器地址栏输入详情页 URL`/loanPricing/workflow-detail/ABC123`
- **THEN** 系统加载详情页面组件,从路由参数中获取 `serialNum`,调用 API 获取对应的流程详情数据并展示
#### Scenario: 详情页面数据加载
- **WHEN** 用户访问流程详情页面,路由参数包含有效的 `serialNum`
- **THEN** 系统在页面 created 钩子中调用 `GET /loanPricing/workflow/{serialNum}` 接口获取详情数据,显示 loading 状态,数据加载完成后隐藏 loading 并展示详情信息

View File

@@ -1,57 +0,0 @@
# 任务清单:将流程详情从弹窗改为独立页面
## 前端任务
### 1. 创建详情页面组件
- [x] 创建 `ruoyi-ui/src/views/loanPricing/workflow/detail.vue`
- [x] 实现页面模板el-page-header + el-card + el-descriptions
- [x] 实现数据获取逻辑(从 route.params 获取 serialNum
- [x] 实现 loading 状态和错误处理
- [x] 实现返回逻辑router.go(-1) 或跳转列表页)
### 2. 配置动态路由
- [x]`ruoyi-ui/src/router/index.js``dynamicRoutes` 中添加详情页路由
- [x] 配置路由参数 `:serialNum`
- [x] 配置权限 `loanPricing:workflow:query`
- [x] 配置 `activeMenu: '/loanPricing/workflow'` 保持菜单高亮
### 3. 修改列表页组件
- [x] 修改 `index.vue` 中的 `handleView()` 方法,改为路由跳转
- [x] 移除 `openDetail` 状态变量
- [x] 移除 `detail` 数据对象
- [x] 移除详情对话框模板(`<el-dialog>`
- [x] 移除 API 导入中的 `getWorkflow`(如果详情页单独导入)
## 验证任务
### 4. 功能测试
- [ ] 测试从列表页点击"查看"按钮跳转到详情页
- [ ] 测试详情页正确显示流程信息
- [ ] 测试详情页返回按钮正常工作
- [ ] 测试面包屑导航正确高亮"流程列表"
- [ ] 测试无权限用户无法访问详情页403 或跳转登录)
- [ ] 测试访问无效的 serialNum显示错误提示
### 5. UI 测试
- [ ] 测试详情信息完整显示(所有字段)
- [ ] 测试长字段(如业务方流水号)正确显示
- [ ] 测试布尔值字段正确转换为"是/否"
- [ ] 测试移动端响应式布局(单列显示)
### 6. 回归测试
- [ ] 确认流程列表页面功能正常(查询、筛选、分页)
- [ ] 确认新增流程功能正常
- [ ] 确认其他菜单页面不受影响
## 依赖关系
- 任务 1创建详情页面和任务 2配置路由可以并行进行
- 任务 3修改列表页依赖任务 2 完成(确保路由存在)
- 所有验证任务4-6依赖任务 1-3 完成
## 估算
- 任务 1创建详情页面组件核心任务- 已完成
- 任务 2配置动态路由简单任务- 已完成
- 任务 3修改列表页组件简单任务- 已完成
- 任务 4-6测试验证重要任务- 待用户进行手动测试

View File

@@ -1,149 +0,0 @@
# 设计文档:抽离流程创建对话框组件
## 组件设计
### WorkflowCreateDialog.vue 组件
**位置**`ruoyi-ui/src/views/loanPricing/workflow/components/WorkflowCreateDialog.vue`
**职责**:负责利率定价流程创建表单的展示和交互逻辑
#### Props
| 名称 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `visible` | `Boolean` | `false` | 对话框显示状态v-model 绑定) |
#### Events
| 事件名 | 参数 | 说明 |
|--------|------|------|
| `update:visible` | `(value: Boolean)` | 对话框显示状态变化时触发 |
| `success` | - | 创建成功后触发,父组件可刷新列表 |
#### 内部状态
```javascript
data() {
return {
activeTab: 'basic', // 当前激活的标签页
form: {}, // 表单数据
rules: {} // 表单验证规则
}
}
```
#### 表单字段结构
保持与现有实现一致,包含以下分组:
1. **基本信息** 标签页 (`basic`)
- 客户内码 (`custIsn`) - 必填
- 客户名称 (`custName`)
- 客户类型 (`custType`) - 必填,下拉选择
- 证件类型 (`idType`) - **下拉选择**(身份证、统一社会信用代码)
2. **贷款信息** 标签页 (`loan`)
- 申请金额 (`applyAmt`) - 必填
- 贷款利率 (`loanRate`) - 必填
- 担保方式 (`guarType`) - 必填,下拉选择
- 贷款用途 (`loanPurpose`) - 下拉选择
- 抵质押类型 (`collType`) - 下拉选择
- 是否有经营佐证 (`bizProofActive`) - 开关
- 抵质押物三方所有 (`collThirdPartyActive`) - 开关
3. **中间业务标识** 标签页 (`mid`)
- 个人快捷支付 (`midPerQuickPayActive`) - 开关
- 个人电费代扣 (`midPerEleDdcActive`) - 开关
- 企业电费代扣 (`midEntEleDdcActive`) - 开关
- 企业水费代扣 (`midEntWaterDdcActive`) - 开关
4. **企业标识** 标签页 (`ent`)
- 净身企业 (`isCleanEntActive`) - 开关
- 开立基本结算账户 (`hasSettleAcctActive`) - 开关
- 制造业企业 (`isManufacturingActive`) - 开关
- 省农担担保贷款 (`isAgriGuarActive`) - 开关
- 纳税信用等级A级 (`isTaxAActive`) - 开关
- 县级及以上农业龙头企业 (`isAgriLeadingActive`) - 开关
- 普惠小微借款人 (`isInclusiveFinanceActive`) - 开关
#### 方法
| 方法名 | 说明 |
|--------|------|
| `reset()` | 重置表单到初始状态 |
| `cancel()` | 关闭对话框并重置表单 |
| `submitForm()` | 验证并提交表单 |
### index.vue 修改
**移除内容**
- 删除对话框相关的模板代码(第 82-256 行)
- 删除 `openCreate``activeTab``form``rules` 状态
- 删除 `handleAdd()``reset()``cancelCreate()``submitForm()` 方法
**新增内容**
- 导入 `WorkflowCreateDialog` 组件
- 注册组件
- 添加 `showCreateDialog` 状态(替代 `openCreate`
- 修改 `handleAdd()` 方法,设置 `showCreateDialog = true`
- 添加 `handleCreateSuccess()` 方法,处理创建成功后刷新列表
## 组件通信流程
```
┌─────────────────────────────────────────────────────────────┐
│ index.vue │
│ ┌─────────────┐ ┌─────────────────────────────────┐ │
│ │ handleAdd() │ ───► │ showCreateDialog = true │ │
│ └─────────────┘ └─────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ showCreateDialog (v-model) │ │
│ ├──────────────────────────────────────────────────────┤ │
│ │ │ │
│ ▼ │ │
│ ┌────────────────────────────────────────────────────┐ │ │
│ │ WorkflowCreateDialog.vue │ │ │
│ │ │ │ │
│ │ ◄────── visible (prop) ───────┐ │ │ │
│ │ │ │ │ │
│ │ ───────► update:visible ──────┘ │ │ │
│ │ │ │ │
│ │ submitForm() ──► API 调用 ──► @success 事件 ────────┼──┘
│ │ │
│ └────────────────────────────────────────────────────┘
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ handleCreateSuccess() ──► getList() ──► 刷新列表 │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
## 证件类型下拉框实现
```vue
<el-form-item label="证件类型" prop="idType">
<el-select v-model="form.idType" placeholder="请选择证件类型" style="width: 100%">
<el-option label="身份证" value="身份证" />
<el-option label="统一社会信用代码" value="统一社会信用代码" />
</el-select>
</el-form-item>
```
## 目录结构
```
ruoyi-ui/src/views/loanPricing/workflow/
├── components/
│ └── WorkflowCreateDialog.vue # 新增:创建对话框组件
├── detail.vue # 详情页面
└── index.vue # 列表页面(修改)
```
## 兼容性考虑
- 组件使用 Vue 2.6.12 的 Options API 风格
- 使用 Element UI 2.15.14 组件
- 保持与现有代码风格一致
- 确保表单验证规则和行为不变

View File

@@ -1,39 +0,0 @@
# 提案:抽离流程创建对话框为独立组件并修改证件类型字段
## 概述
将利率定价流程创建对话框从列表页面组件中抽离为独立的可复用组件,同时将证件类型字段从输入框改为下拉框(选项:身份证、统一社会信用代码)。
## 背景
当前流程列表页面 ([`index.vue`](ruoyi-ui/src/views/loanPricing/workflow/index.vue)) 中,创建流程对话框的代码直接嵌入在列表组件中,导致单个文件超过 400 行。这不利于代码维护和复用。同时,证件类型字段使用输入框,用户需要手动输入,容易出错。
## 目标
1. **组件化**:将创建流程对话框抽离为独立组件 `WorkflowCreateDialog.vue`,放置在 `ruoyi-ui/src/views/loanPricing/workflow/components/` 目录
2. **改进用户体验**:将证件类型改为下拉框,提供固定选项(身份证、统一社会信用代码)
3. **保持功能一致**:确保抽离后功能与现有实现完全一致
## 影响范围
- **新增文件**`ruoyi-ui/src/views/loanPricing/workflow/components/WorkflowCreateDialog.vue`
- **修改文件**`ruoyi-ui/src/views/loanPricing/workflow/index.vue`
- **修改规格**`loan-pricing-workflow-ui` 规格中的"流程创建"需求
## 涉及能力
- **loan-pricing-workflow-ui**:前端用户界面规格
## 实施计划
1. 创建 `WorkflowCreateDialog.vue` 组件,包含所有表单逻辑
2. 修改 `index.vue`,引入并使用新组件
3. 更新 `loan-pricing-workflow-ui` 规格,修改证件类型字段描述
4. 测试验证功能完整性
## 验收标准
- [ ] 创建对话框组件独立存在,可正常导入使用
- [ ] 证件类型为下拉框,选项为"身份证"和"统一社会信用代码"
- [ ] 所有表单验证、提交逻辑正常工作
- [ ] 列表页面功能无退化

View File

@@ -1,58 +0,0 @@
# loan-pricing-workflow-ui 规格变更
## MODIFIED Requirements
### Requirement: 流程创建
系统 SHALL 提供创建新利率定价流程的功能,通过独立的对话框组件收集必要信息。
#### Scenario: 打开创建表单
- **WHEN** 用户在流程列表页面且具有 `loanPricing:workflow:create` 权限,点击"新增"按钮
- **THEN** 系统通过 `WorkflowCreateDialog` 组件弹出创建流程表单对话框,显示所有必填和可选字段
#### Scenario: 表单字段显示
- **WHEN** 用户打开创建流程表单对话框
- **THEN** 系统显示以下字段分组:
- 基本信息:客户内码(必填)、客户名称、客户类型(必填,下拉选择:个人/企业)、**证件类型(下拉选择:身份证/统一社会信用代码)**
- 贷款信息:申请金额(必填)、贷款利率(必填)、担保方式(必填,下拉选择:信用/保证/抵押/质押、贷款用途下拉选择consumer/business
- 中间业务标识(个人):个人快捷支付(开关)、个人电费代扣(开关)
- 中间业务标识(企业):企业电费代扣(开关)、企业水费代扣(开关)
- 企业标识净身企业开关、开立基本结算账户开关、制造业企业开关、省农担担保贷款开关、纳税信用等级A级开关、县级及以上农业龙头企业开关、普惠小微借款人开关
- 抵质押信息:抵质押类型(下拉选择:一线/一类/二类)、抵质押物三方所有(开关)、是否有经营佐证(开关)
- 固定字段机构编码隐藏固定值931000、运行模式隐藏固定值1
#### Scenario: 选择证件类型
- **WHEN** 用户在创建流程表单中点击证件类型下拉框
- **THEN** 系统显示两个选项:"身份证"和"统一社会信用代码",用户选择其中一个
#### Scenario: 表单验证
- **WHEN** 用户填写表单并点击确定按钮
- **THEN** 系统验证必填字段:客户内码、客户类型、担保方式、申请金额、贷款利率,如有缺失则显示错误提示
#### Scenario: 提交创建成功
- **WHEN** 用户填写完必填字段并点击确定按钮,后端返回成功响应
- **THEN** 对话框组件触发 `success` 事件,父组件关闭对话框,显示成功提示消息,刷新列表数据
#### Scenario: 取消创建
- **WHEN** 用户点击取消按钮或对话框关闭按钮
- **THEN** 对话框组件触发 `update:visible` 事件,父组件关闭对话框,不保存数据,不刷新列表
#### Scenario: 新增按钮权限控制
- **WHEN** 用户不具有 `loanPricing:workflow:create` 权限
- **THEN** 系统不显示"新增"按钮
### Requirement: 创建对话框组件架构
系统 SHALL 将创建流程对话框实现为独立的 Vue 组件,支持复用和维护。
#### Scenario: 组件导入和注册
- **WHEN** 开发者在 `index.vue` 中需要使用创建对话框功能
- **THEN** 系统从 `@/views/loanPricing/workflow/components/WorkflowCreateDialog` 导入组件并注册
#### Scenario: 组件属性绑定
- **WHEN** 父组件使用 `WorkflowCreateDialog` 组件
- **THEN** 系统支持通过 `v-model:visible``visible` prop + `update:visible` 事件控制对话框显示状态
#### Scenario: 组件事件处理
- **WHEN** 用户成功创建流程
- **THEN** 组件触发 `success` 事件,父组件可监听该事件执行列表刷新等操作

View File

@@ -1,96 +0,0 @@
# 实施任务清单
## 任务列表
### 1. 创建组件目录结构
- [x] 创建 `ruoyi-ui/src/views/loanPricing/workflow/components/` 目录
- **验证**: 目录创建成功,使用 `ls``dir` 确认
### 2. 创建 WorkflowCreateDialog.vue 组件
- [x] 创建组件文件,包含完整的对话框模板
- [x] 实现 props`visible`(对话框显示状态)
- [x] 实现 emits`update:visible``success`
- [x] 实现表单数据结构(保持与原实现一致)
- [x] 实现表单验证规则
- [x] 实现四个标签页的表单字段
- [x] **将证件类型改为 el-select 下拉框**,选项为"身份证"和"统一社会信用代码"
- [x] 实现 `reset()` 方法:重置表单到初始状态
- [x] 实现 `cancel()` 方法:关闭对话框并重置表单
- [x] 实现 `submitForm()` 方法:验证并提交表单
- [x] 导入 `createWorkflow` API 函数
- **验证**: 组件文件创建成功,无 ESLint 错误
### 3. 修改 index.vue 引入新组件
- [x]`index.vue` 顶部导入 `WorkflowCreateDialog` 组件
- [x] 在 components 选项中注册组件
- **验证**: 导入和注册语法正确
### 4. 修改 index.vue 模板
- [x] 删除原有的对话框模板代码(第 82-256 行)
- [x] 添加 `<workflow-create-dialog>` 组件标签
- [x] 绑定 `v-model:visible="showCreateDialog"`
- [x] 监听 `@success` 事件调用 `handleCreateSuccess`
- **验证**: 模板语法正确,组件标签正确使用
### 5. 修改 index.vue 数据和逻辑
- [x] 移除 `openCreate` 状态,替换为 `showCreateDialog`
- [x] 移除 `activeTab` 状态
- [x] 移除 `form` 状态
- [x] 移除 `rules` 状态
- [x] 修改 `handleAdd()` 方法:设置 `showCreateDialog = true`
- [x] 添加 `handleCreateSuccess()` 方法:显示成功消息并调用 `getList()`
- [x] 删除 `reset()` 方法
- [x] 删除 `cancelCreate()` 方法
- [x] 删除 `submitForm()` 方法
- [x] 删除 `createWorkflow` 导入(已移至组件内)
- **验证**: 修改后的代码无语法错误
### 6. 手动功能测试
- [ ] 启动前端开发服务器 (`npm run dev`)
- [ ] 登录系统 (admin/admin123)
- [ ] 导航至"利率定价管理 > 流程列表"
- [ ] 点击"新增"按钮,验证对话框正常弹出
- [ ] 切换各个标签页,验证表单字段正确显示
- [ ] **点击证件类型下拉框,验证选项为"身份证"和"统一社会信用代码"**
- [ ] 测试表单验证:不填必填项提交,验证错误提示
- [ ] 填写完整表单并提交,验证创建成功
- [ ] 验证创建成功后列表自动刷新
- [ ] 测试取消按钮,验证对话框关闭且不保存
- **验证**: 所有功能正常工作
### 7. 代码质量检查
- [x] 检查组件命名和文件命名符合项目规范
- [x] 检查代码格式符合项目 ESLint 配置
- [x] 检查注释完整,关键逻辑有说明
- **验证**: 代码符合项目规范
## 任务依赖关系
```
1. 创建组件目录结构
├──► 2. 创建 WorkflowCreateDialog.vue 组件
│ │
│ ├──► 3. 修改 index.vue 引入新组件
│ │ │
│ │ ├──► 4. 修改 index.vue 模板
│ │ │ │
│ │ │ ├──► 5. 修改 index.vue 数据和逻辑
│ │ │ │ │
│ │ │ │ └──► 6. 手动功能测试
│ │ │ │ │
│ │ │ │ └──► 7. 代码质量检查
│ │ │ │
│ │ │ └──► (并行) 6. 手动功能测试
│ │ │
│ │ └──► (并行) 6. 手动功能测试
│ │
│ └──► (并行) 6. 手动功能测试
└──► (并行) 6. 手动功能测试
```
## 可并行任务
- 任务 3、4、5 可以在任务 2 完成后并行执行
- 任务 7 可与任务 6 并行执行

View File

@@ -1,23 +0,0 @@
# Change: 优化流程详情页面布局
## Why
当前流程详情页面 ([`ruoyi-ui/src/views/loanPricing/workflow/detail.vue`](../../ruoyi-ui/src/views/loanPricing/workflow/detail.vue)) 采用简单的标签页布局,所有信息平铺展示,缺乏信息层次感。用户需要在不同标签页之间切换才能查看关键信息,无法快速获取最重要的数据概览。页面视觉层次不够清晰,信息利用率不高。
## What Changes
- **页面布局重构**: 采用信息密集型两栏布局
- 左侧(约 30% 宽度):展示关键信息摘要卡片(业务方流水号、客户名称、申请金额、贷款利率等核心字段)
- 右侧(约 70% 宽度):保留现有标签页,展示完整的流程详细信息
- **页面头部简化**: 移除 `el-page-header`,使用简洁的页面标题,返回按钮移至页面右上角
- **样式优化**:
- 为左侧摘要卡片添加适当的阴影和圆角
- 优化卡片内部间距和字体大小
- 保持现有的简洁数据展示风格(不添加图标或额外的高亮效果)
- **响应式支持**: 在小屏幕设备上自动调整为单栏垂直布局
## Impact
- 受影响的规范: `loan-pricing-workflow-ui`
- 受影响的代码: [`ruoyi-ui/src/views/loanPricing/workflow/detail.vue`](../../ruoyi-ui/src/views/loanPricing/workflow/detail.vue)
- 破坏性变更: 无(仅改变 UI 布局,不影响功能和 API

View File

@@ -1,34 +0,0 @@
## MODIFIED Requirements
### Requirement: 流程详情查看
系统 SHALL 提供流程详情查看功能,以独立页面形式展示完整的流程信息,采用信息密集型两栏布局。
#### Scenario: 查看流程详情
- **WHEN** 用户在流程列表页面且具有 `loanPricing:workflow:query` 权限,点击列表中某条记录的"查看"按钮
- **THEN** 系统导航至流程详情独立页面,展示两栏布局:
- **左侧摘要卡片**(约 30% 宽度):显示核心信息
- 业务方流水号
- 客户名称
- 客户类型
- 申请金额
- 贷款利率
- 担保方式
- **右侧详情区域**(约 70% 宽度):使用标签页组织完整信息
- 基本信息标签页:机构编码、运行模式、客户内码、证件类型
- 业务信息标签页:贷款用途、是否有经营佐证、抵质押类型、抵质押物三方所有
- 中间业务标识标签页:个人快捷支付、个人电费代扣、企业电费代扣、企业水费代扣
- 企业标识标签页净身企业、开立基本结算账户、制造业企业、省农担担保贷款、纳税信用等级A级、县级及以上农业龙头企业、普惠小微借款人
- 其他信息标签页:创建时间、创建者、更新时间、更新者
#### Scenario: 页面头部和导航
- **WHEN** 用户访问流程详情页面
- **THEN** 系统显示简洁的页面标题区域,右上角放置返回按钮,移除原有的面包屑导航组件
#### Scenario: 响应式布局适配
- **WHEN** 用户在屏幕宽度小于 768px 的设备上访问流程详情页面
- **THEN** 系统自动调整为单栏垂直布局,左侧摘要卡片在上方,右侧详情标签页在下方
#### Scenario: 返回上一页
- **WHEN** 用户点击页面右上角的返回按钮
- **THEN** 系统返回至流程列表页面

View File

@@ -1,19 +0,0 @@
## 1. 实现页面布局重构
- [x] 1.1 创建左侧摘要卡片组件结构
- [x] 1.2 创建右侧标签页详情区域
- [x] 1.3 实现响应式布局(使用 `el-col``xs` 断点)
- [x] 1.4 调整页面头部(移除 `el-page-header`,添加返回按钮到右上角)
## 2. 样式优化
- [x] 2.1 添加卡片阴影和圆角样式
- [x] 2.2 优化间距和字体大小
- [x] 2.3 调整两栏布局的间距(`el-row``gutter` 属性)
## 3. 测试验证
- [x] 3.1 测试页面在不同屏幕尺寸下的显示效果
- [x] 3.2 验证所有数据字段正确显示
- [x] 3.3 确认返回按钮功能正常
- [x] 3.4 验证标签页切换功能正常

View File

@@ -1,80 +0,0 @@
# Design: 移除流程创建弹窗的 Tab 栏布局
## Current Implementation
当前 `WorkflowCreateDialog.vue` 使用 `el-tabs` 组件组织表单字段:
```vue
<el-tabs v-model="activeTab">
<el-tab-pane label="基本信息" name="basic">
<!-- 客户内码客户名称客户类型证件类型 -->
</el-tab-pane>
<el-tab-pane label="贷款信息" name="loan">
<!-- 申请金额贷款利率担保方式贷款用途抵质押类型是否有经营佐证抵质押物三方所有 -->
</el-tab-pane>
<el-tab-pane label="中间业务标识" name="mid">
<!-- 个人快捷支付个人电费代扣企业电费代扣企业水费代扣 -->
</el-tab-pane>
<el-tab-pane label="企业标识" name="ent">
<!-- 净身企业开立基本结算账户制造业企业省农担担保贷款纳税信用等级A级县级及以上农业龙头企业普惠小微借款人 -->
</el-tab-pane>
</el-tabs>
```
## Proposed Implementation
使用 Element UI 的 `el-divider` 组件作为分组标题,移除 `el-tabs``el-tab-pane`
```vue
<el-form ref="form" :model="form" :rules="rules" label-width="140px">
<!-- 基本信息 -->
<el-divider content-position="left">基本信息</el-divider>
<el-row>
<el-col :span="12">
<el-form-item label="客户内码" prop="custIsn">
<el-input v-model="form.custIsn" placeholder="请输入客户内码" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="客户名称" prop="custName">
<el-input v-model="form.custName" placeholder="请输入客户名称" />
</el-form-item>
</el-col>
</el-row>
<!-- ... 其他基本信息字段 ... -->
<!-- 贷款信息 -->
<el-divider content-position="left">贷款信息</el-divider>
<!-- ... 贷款信息字段 ... -->
<!-- 中间业务标识 -->
<el-divider content-position="left">中间业务标识</el-divider>
<!-- ... 中间业务标识字段 ... -->
<!-- 企业标识 -->
<el-divider content-position="left">企业标识</el-divider>
<!-- ... 企业标识字段 ... -->
</el-form>
```
同时需要移除 `data()` 中的 `activeTab` 属性。
## CSS Styling
`el-divider` 添加适当的外边距,确保分组标题与表单字段之间有清晰的视觉分隔:
```css
.el-divider {
margin: 16px 0 20px 0;
font-weight: bold;
}
```
或使用 `<style scoped>` 在组件内定义。
## Rationale
1. **单一表单布局**:所有字段在同一页面可见,用户可以快速浏览和填写
2. **分组标题**:使用 `el-divider``content-position` 属性显示分组标题,保持清晰的视觉层次
3. **滚动支持**:对话框内容区域可滚动,支持大量字段的显示
4. **保持验证逻辑**:不需要修改表单验证逻辑,`el-form` 的验证机制仍然有效

View File

@@ -1,43 +0,0 @@
# Proposal: 移除流程创建弹窗的 Tab 栏布局
## Summary
修改 `WorkflowCreateDialog.vue` 组件,将当前使用 `el-tabs` 分组的多 tab 栏布局改为单一表单的垂直布局,使用分组标题(如 Element UI 的 `el-divider` 或自定义标题)来区分不同的字段区域。
## Motivation
当前实现使用 `el-tabs` 将表单字段分为四个标签页(基本信息、贷款信息、中间业务标识、企业标识),存在以下问题:
1. **用户体验不佳**:用户需要在多个 tab 之间切换才能完成表单填写,增加了操作步骤
2. **表单可见性差**:用户无法一次性看到所有需要填写的字段,可能遗漏某些选项
3. **确认验证困难**:点击"确定"时,用户可能看不到其他 tab 中必填字段的验证提示
## Proposed Solution
移除 `el-tabs` 组件,改用单一表单布局,使用视觉分隔符或分组标题来组织字段:
- **基本信息**:使用 `el-divider` 或分组标题
- **贷款信息**:使用 `el-divider` 或分组标题
- **中间业务标识**:使用 `el-divider` 或分组标题
- **企业标识**:使用 `el-divider` 或分组标题
- **抵质押信息**:整合到"贷款信息"分组下或单独分组
所有字段垂直排列,用户可以滚动查看和填写。
## Alternatives Considered
1. **保持 tab 栏但优化布局**:不解决用户体验问题
2. **使用手风琴折叠面板**:仍需要展开/收起操作,不如单一表单直观
3. **使用分步表单Steps**:增加了操作步骤,不适合简单的表单填写场景
## Impact
- **Scope**: 仅影响 `WorkflowCreateDialog.vue` 组件的 UI 布局
- **Breaking Changes**: 无UI 改进,功能不变)
- **Dependencies**: 无新增依赖
## Related Changes
- Modifies: `loan-pricing-workflow-ui` spec (Requirement: 流程创建)
- Related Files:
- `ruoyi-ui/src/views/loanPricing/workflow/components/WorkflowCreateDialog.vue`

View File

@@ -1,36 +0,0 @@
# loan-pricing-workflow-ui Spec Delta
## MODIFIED Requirements
### Requirement: 流程创建
系统 SHALL 提供创建新利率定价流程的功能,通过表单对话框收集必要信息。
#### Scenario: 打开创建表单
- **WHEN** 用户在流程列表页面且具有 `loanPricing:workflow:create` 权限,点击"新增"按钮
- **THEN** 系统弹出创建流程表单对话框,在单一表单页面中垂直显示所有必填和可选字段,使用分组标题区分不同的字段区域
#### Scenario: 表单字段显示
- **WHEN** 用户打开创建流程表单对话框
- **THEN** 系统在单一表单中显示以下字段分组,使用分隔符或分组标题区分:
- **基本信息**分组:客户内码(必填)、客户名称、客户类型(必填,下拉选择:个人/企业)、证件类型
- **贷款信息**分组:申请金额(必填)、贷款利率(必填)、担保方式(必填,下拉选择:信用/保证/抵押/质押、贷款用途下拉选择consumer/business、抵质押类型下拉选择一线/一类/二类)、是否有经营佐证(开关)、抵质押物三方所有(开关)
- **中间业务标识**分组:个人快捷支付(开关)、个人电费代扣(开关)、企业电费代扣(开关)、企业水费代扣(开关)
- **企业标识**分组净身企业开关、开立基本结算账户开关、制造业企业开关、省农担担保贷款开关、纳税信用等级A级开关、县级及以上农业龙头企业开关、普惠小微借款人开关
- **固定字段**机构编码隐藏固定值931000、运行模式隐藏固定值1
#### Scenario: 表单验证
- **WHEN** 用户填写表单并点击确定按钮
- **THEN** 系统在同一表单页面中验证必填字段:客户内码、客户类型、担保方式、申请金额、贷款利率,如有缺失则在对应字段位置显示错误提示
#### Scenario: 提交创建成功
- **WHEN** 用户填写完必填字段并点击确定按钮,后端返回成功响应
- **THEN** 系统关闭对话框,显示成功提示消息,刷新列表数据
#### Scenario: 取消创建
- **WHEN** 用户点击取消按钮或对话框关闭按钮
- **THEN** 系统关闭对话框,不保存数据,不刷新列表
#### Scenario: 新增按钮权限控制
- **WHEN** 用户不具有 `loanPricing:workflow:create` 权限
- **THEN** 系统不显示"新增"按钮

View File

@@ -1,21 +0,0 @@
# Tasks
1. **修改 WorkflowCreateDialog.vue 组件布局**
- 移除 `el-tabs``el-tab-pane` 组件
- 添加分组标题/分隔符来区分字段区域
- 保持所有表单字段和验证规则不变
- 验证表单提交功能正常工作
2. **测试验证**
- 测试所有必填字段的验证是否正常
- 测试表单提交功能
- 测试取消和关闭对话框功能
- 确认在不同屏幕尺寸下的显示效果
## Validation Criteria
- [x] 移除 tab 栏,所有字段在单一表单中可见
- [x] 使用分组标题/分隔符清晰区分字段区域
- [x] 表单验证功能正常
- [x] 表单提交功能正常
- [x] 取消和关闭功能正常

View File

@@ -1,360 +0,0 @@
# Design: 拆分个人和企业利率定价发起接口
## 数据库变更
### 缺失字段分析
经过对比 `person.csv``corp.csv` 中定义的字段与现有数据库表 `loan_pricing_workflow`,发现以下字段缺失:
#### 个人客户缺失字段
| 字段名 | 中文名 | 类型 | 说明 |
|-----------|------|--------------|-------------------------|
| id_num | 证件号码 | varchar(100) | 存储个人身份证号或其他证件号码 |
| loan_loop | 循环功能 | varchar(10) | 贷款合同是否开通循环功能true/false |
#### 企业客户缺失字段
| 字段名 | 中文名 | 类型 | 说明 |
|-----------------------|------------|--------------|----------------------------------|
| id_num | 证件号码 | varchar(100) | 存储企业统一社会信用代码或其他证件号码 |
| is_trade_construction | 贸易和建筑业企业标识 | varchar(10) | 抵押类贸易和建筑业企业上调20BPtrue/false |
| is_green_loan | 绿色贷款 | varchar(10) | 绿色贷款标识true/false |
| is_tech_ent | 科技型企业 | varchar(10) | 科技型企业标识true/false |
| loan_term | 贷款期限 | varchar(50) | 贷款期限,单位:月/年 |
### 数据库迁移 SQL
```sql
-- 添加缺失的字段到 loan_pricing_workflow 表
-- 个人和企业共同需要的字段
ALTER TABLE `loan_pricing_workflow` ADD COLUMN `id_num` varchar(100) DEFAULT NULL COMMENT '证件号码' AFTER `id_type`;
-- 个人客户专用字段
ALTER TABLE `loan_pricing_workflow` ADD COLUMN `loan_loop` varchar(10) DEFAULT NULL COMMENT '循环功能: true/false' AFTER `biz_proof`;
-- 企业客户专用字段
ALTER TABLE `loan_pricing_workflow` ADD COLUMN `is_trade_construction` varchar(10) DEFAULT NULL COMMENT '贸易和建筑业企业标识: true/false抵质押类上调20BP' AFTER `is_agri_guar`;
ALTER TABLE `loan_pricing_workflow` ADD COLUMN `is_green_loan` varchar(10) DEFAULT NULL COMMENT '绿色贷款: true/false' AFTER `is_agri_guar`;
ALTER TABLE `loan_pricing_workflow` ADD COLUMN `is_tech_ent` varchar(10) DEFAULT NULL COMMENT '科技型企业: true/false' AFTER `is_agri_guar`;
ALTER TABLE `loan_pricing_workflow` ADD COLUMN `loan_term` varchar(50) DEFAULT NULL COMMENT '贷款期限' AFTER `apply_amt`;
```
### Entity 类更新
`LoanPricingWorkflow.java` 需要添加以下属性:
```java
/** 证件号码 */
private String idNum;
/** 循环功能: true/false */
private String loanLoop;
/** 贸易和建筑业企业标识: true/false */
private String isTradeConstruction;
/** 绿色贷款: true/false */
private String isGreenLoan;
/** 科技型企业: true/false */
private String isTechEnt;
/** 贷款期限 */
private String loanTerm;
```
## 架构设计
### 1. DTO 结构设计
#### PersonalLoanPricingCreateDTO个人客户发起DTO
```java
@Data
public class PersonalLoanPricingCreateDTO {
@NotBlank(message = "客户内码不能为空")
private String custIsn;
@NotBlank(message = "客户类型不能为空")
private String custType; // 固定值 "个人"
@NotBlank(message = "担保方式不能为空")
private String guarType; // 可选值:信用,保证,抵押,质押
private String custName;
private String idType;
private String idNum;
@NotBlank(message = "申请金额不能为空")
private String applyAmt; // 单位:元
private String bizProof; // 是否有经营佐证
private String loanLoop; // 循环功能
private String collType; // 抵质押类型
private String collThirdParty; // 抵质押物是否三方所有
}
```
#### CorporateLoanPricingCreateDTO企业客户发起DTO
```java
@Data
public class CorporateLoanPricingCreateDTO {
@NotBlank(message = "客户内码不能为空")
private String custIsn;
@NotBlank(message = "客户类型不能为空")
private String custType; // 固定值 "企业"
@NotBlank(message = "担保方式不能为空")
private String guarType; // 可选值:信用,保证,抵押,质押
private String custName;
private String idType;
private String idNum;
@NotBlank(message = "申请金额不能为空")
private String applyAmt; // 单位:元
private String isAgriGuar; // 省农担担保贷款
private String isGreenLoan; // 绿色贷款
private String isTechEnt; // 科技型企业
private String loanTerm; // 贷款期限
private String collType; // 抵质押类型
private String collThirdParty; // 抵质押物是否三方所有
}
```
### 2. 接口设计
#### Controller 层
```java
@RestController
@RequestMapping("/loanPricing/workflow")
public class LoanPricingWorkflowController extends BaseController {
// 原有接口(保留)
@PostMapping("/create")
public AjaxResult create(@Validated @RequestBody LoanPricingWorkflow loanPricingWorkflow)
// 新增:个人客户发起接口
@PostMapping("/create/personal")
public AjaxResult createPersonal(@Validated @RequestBody PersonalLoanPricingCreateDTO dto)
// 新增:企业客户发起接口
@PostMapping("/create/corporate")
public AjaxResult createCorporate(@Validated @RequestBody CorporateLoanPricingCreateDTO dto)
}
```
#### Service 层接口
```java
public interface ILoanPricingWorkflowService {
// 原有方法(保留兼容)
LoanPricingWorkflow createLoanPricing(LoanPricingWorkflow loanPricingWorkflow);
// 新增:个人客户发起
LoanPricingWorkflow createPersonalLoanPricing(PersonalLoanPricingCreateDTO dto);
// 新增:企业客户发起
LoanPricingWorkflow createCorporateLoanPricing(CorporateLoanPricingCreateDTO dto);
}
```
### 3. 字段映射关系
| 字段类别 | 个人字段 | 企业字段 |
|------|------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------|
| 共同字段 | custIsn, custType, guarType, custName, idType, idNum, applyAmt, collType, collThirdParty | |
| 个人特有 | bizProof是否有经营佐证, loanLoop循环功能 | |
| 企业特有 | | isAgriGuar省农担担保贷款, isGreenLoan绿色贷款, isTechEnt科技型企业, isTradeConstruction贸易和建筑业企业, loanTerm贷款期限 |
### 4. 实现细节
#### DTO 转 Entity 转换器
创建一个转换工具类,将 DTO 转换为 `LoanPricingWorkflow` 实体:
```java
public class LoanPricingConverter {
public static LoanPricingWorkflow toEntity(PersonalLoanPricingCreateDTO dto) {
LoanPricingWorkflow entity = new LoanPricingWorkflow();
// 映射共同字段
entity.setCustIsn(dto.getCustIsn());
entity.setCustType("个人");
entity.setCustName(dto.getCustName());
entity.setIdType(dto.getIdType());
entity.setIdNum(dto.getIdNum());
entity.setGuarType(dto.getGuarType());
entity.setApplyAmt(dto.getApplyAmt());
entity.setCollType(dto.getCollType());
entity.setCollThirdParty(dto.getCollThirdParty());
// 映射个人特有字段
entity.setBizProof(dto.getBizProof());
entity.setLoanLoop(dto.getLoanLoop());
return entity;
}
public static LoanPricingWorkflow toEntity(CorporateLoanPricingCreateDTO dto) {
LoanPricingWorkflow entity = new LoanPricingWorkflow();
// 映射共同字段
entity.setCustIsn(dto.getCustIsn());
entity.setCustType("企业");
entity.setCustName(dto.getCustName());
entity.setIdType(dto.getIdType());
entity.setIdNum(dto.getIdNum());
entity.setGuarType(dto.getGuarType());
entity.setApplyAmt(dto.getApplyAmt());
entity.setCollType(dto.getCollType());
entity.setCollThirdParty(dto.getCollThirdParty());
// 映射企业特有字段
entity.setIsAgriGuar(dto.getIsAgriGuar());
entity.setIsGreenLoan(dto.getIsGreenLoan());
entity.setIsTechEnt(dto.getIsTechEnt());
entity.setIsTradeConstruction(dto.getIsTradeConstruction());
entity.setLoanTerm(dto.getLoanTerm());
return entity;
}
}
```
### 5. 验证策略
#### 个人客户验证
- 必填字段custIsn, custType, guarType, applyAmt
- 枚举验证guarType 必须是"信用/保证/抵押/质押"之一
#### 企业客户验证
- 必填字段custIsn, custType, guarType, applyAmt
- 枚举验证guarType 必须是"信用/保证/抵押/质押"之一
### 6. 向后兼容性策略
1. 保留原有 `POST /loanPricing/workflow/create` 接口
2. 新旧接口共存,前端可自由选择使用
3. 不添加 @Deprecated 标记,保持接口的可用性
## 技术决策
### 为什么使用两个独立的 DTO 而不是一个带条件验证的 DTO
1. **类型安全**:编译期就能发现字段错误
2. **API 文档更清晰**Swagger 只显示相关字段
3. **验证更简单**:不需要在 DTO 内部根据类型做条件验证
### 为什么保留原有接口?
1. **多接口共存**:前端可以选择使用新接口或继续使用原有接口
2. **降级方案**:如果新接口有问题,可以快速回退
3. **兼容性**:可能有其他系统调用该接口
## 文件清单
### 数据库相关
- **新增**: `sql/add_missing_fields.sql` - 数据库迁移脚本
### 新增文件
- `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/PersonalLoanPricingCreateDTO.java`
- `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/CorporateLoanPricingCreateDTO.java`
- `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/util/LoanPricingConverter.java`
### 测试文件
- `ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/domain/dto/PersonalLoanPricingCreateDTOTest.java`
- `ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/domain/dto/CorporateLoanPricingCreateDTOTest.java`
- `ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/util/LoanPricingConverterTest.java`
- `test_api/test_personal_create.http` - 个人客户发起接口 HTTP 测试脚本
- `test_api/test_corporate_create.http` - 企业客户发起接口 HTTP 测试脚本
- `test_api/test_backward_compatibility.http` - 向后兼容性测试脚本
### 修改文件
- `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/entity/LoanPricingWorkflow.java` - 添加缺失字段的属性
- `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/controller/LoanPricingWorkflowController.java`
- `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/ILoanPricingWorkflowService.java`
- `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/impl/LoanPricingWorkflowServiceImpl.java`
## 测试脚本示例
### HTTP 测试脚本格式
测试脚本使用 IntelliJ IDEA 的 .http 文件格式,示例如下:
```http
### Token
POST http://localhost:8080/login/test
Content-Type: application/json
{
"username": "admin",
"password": "admin123"
}
> {%
client.test("Request executed successfully", function() {
client.assert(response.status === 200, "Response status is 200");
client.assert(response.body.code === 200, "Response code is 200");
client.global.set("token", response.body.data.token);
});
%}
### -
POST http://localhost:8080/loanPricing/workflow/create/personal
Authorization: Bearer {{token}}
Content-Type: application/json
{
"custIsn": "TEST001",
"custName": "",
"idType": "",
"idNum": "110101199001011234",
"guarType": "",
"applyAmt": "500000",
"bizProof": "true",
"loanLoop": "false"
}
> {%
client.test("Personal loan creation successful", function() {
client.assert(response.status === 200, "Response status is 200");
client.assert(response.body.code === 200, "Response code is 200");
client.assert(response.body.data.custType === "", "Customer type is ");
});
%}
### -
POST http://localhost:8080/loanPricing/workflow/create/corporate
Authorization: Bearer {{token}}
Content-Type: application/json
{
"custIsn": "CORP001",
"custName": "",
"idType": "",
"idNum": "91110000100000000X",
"guarType": "",
"applyAmt": "1000000",
"isAgriGuar": "false",
"isGreenLoan": "true",
"isTechEnt": "true",
"loanTerm": "36"
}
> {%
client.test("Corporate loan creation successful", function() {
client.assert(response.status === 200, "Response status is 200");
client.assert(response.body.code === 200, "Response code is 200");
client.assert(response.body.data.custType === "", "Customer type is ");
});
%}
```

View File

@@ -1,83 +0,0 @@
# Proposal: 拆分个人和企业利率定价发起接口
## 概述
将现有的统一利率定价发起接口 (`POST /loanPricing/workflow/create`) 拆分为两个独立的接口:
- 个人客户发起接口 (`POST /loanPricing/workflow/create/personal`)
- 企业客户发起接口 (`POST /loanPricing/workflow/create/corporate`)
## 背景
当前系统中,`LoanPricingWorkflow` 实体包含了个人和企业客户的所有字段。当发起流程时根据客户类型custType的不同需要填写的字段存在差异
- **个人客户**:需要填写个人特有字段(如是否有经营佐证、循环功能等)
- **企业客户**:需要填写企业特有字段(如贸易和建筑业企业标识、省农担担保贷款、绿色贷款、科技型企业、贷款期限等)
将接口拆分可以带来以下好处:
1. **接口契约更清晰**:每个接口只包含对应客户类型的字段
2. **验证更精确**:可以在 DTO 层面进行字段验证
3. **文档更友好**API 文档可以分别展示个人和企业的字段
4. **维护性更好**:字段变更不会影响另一类型的客户
## 影响范围
### 后端变更
- 创建新的 DTO 类:`PersonalLoanPricingCreateDTO``CorporateLoanPricingCreateDTO`
-`LoanPricingWorkflowController` 中添加两个新接口
- 修改 `ILoanPricingWorkflowService` 接口,添加两个新的创建方法
- 实现 `LoanPricingWorkflowServiceImpl` 中的新方法
- 保留原有接口以保持向后兼容(可选,建议标记为 Deprecated
### 前端变更
> **注:本次变更仅涉及后端,前端暂不修改**
### 数据库变更
需要向 `loan_pricing_workflow` 表添加以下字段:
| 字段名 | 类型 | 说明 | 适用客户 |
|-----------------------|--------------|------------------------|-------|
| id_num | varchar(100) | 证件号码 | 个人、企业 |
| loan_loop | varchar(10) | 循环功能 | 个人 |
| is_trade_construction | varchar(10) | 贸易和建筑业企业标识抵质押类上调20BP | 企业 |
| is_green_loan | varchar(10) | 绿色贷款最多下降5BP | 企业 |
| is_tech_ent | varchar(10) | 科技型企业最多下降5BP | 企业 |
| loan_term | varchar(50) | 贷款期限 | 企业 |
**迁移脚本位置**: `sql/add_missing_fields.sql`
同时需要更新 `LoanPricingWorkflow` Entity 类,添加对应的属性和字段映射注解。
## 设计方案
详见 `design.md`
## 风险和考虑
1. **向后兼容性**:原有接口 `POST /loanPricing/workflow/create` 继续保留
- 原有接口不做标记为 Deprecated 的处理
- 新旧接口共存,供前端自由选择使用
2. **数据迁移**:需要执行数据库迁移脚本添加新字段,但不涉及现有数据的迁移
3. **测试覆盖**:需要为新接口编写测试用例
## 依赖关系
- **数据库迁移必须最先执行**:所有后端开发依赖于新字段添加完成
- 依赖现有的 `LoanPricingWorkflow` 实体
- 依赖现有的 `ILoanPricingWorkflowService` 服务层
## 验收标准
1. **数据库变更**:所有新字段成功添加到数据库表,且可以正确存储和检索数据
2. **Entity 类更新**`LoanPricingWorkflow` 实体类包含所有新增字段的属性和映射
3. **个人客户接口**:个人客户发起接口只接受个人相关的字段
4. **企业客户接口**:企业客户发起接口只接受企业相关的字段
5. **接口功能**:两个接口都能成功创建利率定价流程记录,包括新增字段的保存
6. **字段验证**:字段验证正确生效
7. **API 文档**API 文档正确显示两个接口的差异

View File

@@ -1,105 +0,0 @@
# 企业利率定价流程发起 Capability Spec
## ADDED Requirements
### Requirement: 企业客户利率定价流程发起
系统 SHALL 提供企业客户专用的利率定价流程发起接口 (`POST /loanPricing/workflow/create/corporate`),该接口只接受企业客户相关的字段。
#### Scenario: 成功发起企业客户利率定价流程
- **WHEN** 业务人员通过企业客户发起接口提交包含必填字段(custIsn、guarType、applyAmt)的完整申请
- **THEN** 系统自动生成业务方流水号(serialNum)并保存记录custType 固定为"企业",返回成功响应
#### Scenario: 字段验证-必填字段
- **WHEN** 提交的企业客户申请缺少必填字段(custIsn、guarType、applyAmt)
- **THEN** 系统返回参数验证失败的错误信息
#### Scenario: 字段验证-担保方式枚举值
- **WHEN** 提交的企业客户申请中 guarType 不是"信用"、"保证"、"抵押"、"质押"之一
- **THEN** 系统返回参数验证失败的错误信息
#### Scenario: 记录企业特有字段
- **WHEN** 企业客户申请中包含 isAgriGuar省农担担保贷款、isGreenLoan绿色贷款、isTechEnt科技型企业或 loanTerm贷款期限字段
- **THEN** 系统正确保存这些字段的值
#### Scenario: 自动设置客户类型
- **WHEN** 通过企业客户发起接口创建流程
- **THEN** 系统自动将 custType 设置为"企业",无需客户端传入
#### Scenario: 自动生成业务方流水号
- **WHEN** 发起企业客户利率定价流程时
- **THEN** 系统使用时间戳自动生成唯一的业务方流水号
#### Scenario: 记录创建和更新信息
- **WHEN** 企业客户利率定价流程创建成功
- **THEN** 系统自动记录创建者、创建时间、更新者、更新时间
### Requirement: 企业客户发起接口字段定义
企业客户发起接口 SHALL 接受以下字段:
#### Scenario: 基本信息字段
- **WHEN** 客户端提交企业客户发起请求
- **THEN** 系统接受以下基本信息字段:
- `custIsn`(必填):客户内码
- `custName`:客户名称
- `idType`:证件类型
- `idNum`:证件号码
#### Scenario: 贷款信息字段
- **WHEN** 客户端提交企业客户发起请求
- **THEN** 系统接受以下贷款信息字段:
- `guarType`(必填):担保方式,可选值"信用"、"保证"、"抵押"、"质押"
- `applyAmt`(必填):申请金额,单位:元
- `loanTerm`:贷款期限
#### Scenario: 企业特有字段-优惠条件
- **WHEN** 客户端提交企业客户发起请求
- **THEN** 系统接受以下企业特有优惠条件字段:
- `isAgriGuar`省农担担保贷款省农担担保贷款下调40个BP
- `isGreenLoan`绿色贷款绿色贷款或科技型企业最多下降5BP
- `isTechEnt`科技型企业绿色贷款或科技型企业最多下降5BP
#### Scenario: 贸易和建筑业企业标识
- **WHEN** 企业客户申请中担保方式为抵(质)押类,且企业为贸易和建筑业企业
- **THEN** 系统记录该标识用于后续利率测算时上调20BP
#### Scenario: 抵质押信息字段
- **WHEN** 客户端提交企业客户发起请求
- **THEN** 系统接受以下抵质押信息字段:
- `collType`:抵质押类型
- `collThirdParty`:抵质押物是否三方所有
## MODIFIED Requirements
### Requirement: 利率定价流程发起接口弃用策略
原有的统一发起接口 (`POST /loanPricing/workflow/create`) SHALL 标记为 Deprecated系统 SHALL
继续支持该接口以保证向后兼容,同时引导使用新的个人或企业专用接口。
#### Scenario: 原有接口向后兼容
- **WHEN** 客户端继续使用原有发起接口
- **THEN** 系统继续处理请求并返回正确结果,但建议迁移到新接口
#### Scenario: 原有接口标记为已弃用
- **WHEN** 开发人员查看 API 文档
- **THEN** 原有接口标记为 Deprecated引导使用新的个人或企业专用接口
## Cross-References
- 相关 Capability: `personal-loan-pricing-creation`(个人客户利率定价流程发起)
- 修改自 Capability: `loan-pricing-workflow` 中的"利率定价流程发起"需求

View File

@@ -1,98 +0,0 @@
# 个人利率定价流程发起 Capability Spec
## ADDED Requirements
### Requirement: 个人客户利率定价流程发起
系统 SHALL 提供个人客户专用的利率定价流程发起接口 (`POST /loanPricing/workflow/create/personal`),该接口只接受个人客户相关的字段。
#### Scenario: 成功发起个人客户利率定价流程
- **WHEN** 业务人员通过个人客户发起接口提交包含必填字段(custIsn、guarType、applyAmt)的完整申请
- **THEN** 系统自动生成业务方流水号(serialNum)并保存记录custType 固定为"个人",返回成功响应
#### Scenario: 字段验证-必填字段
- **WHEN** 提交的个人客户申请缺少必填字段(custIsn、guarType、applyAmt)
- **THEN** 系统返回参数验证失败的错误信息
#### Scenario: 字段验证-担保方式枚举值
- **WHEN** 提交的个人客户申请中 guarType 不是"信用"、"保证"、"抵押"、"质押"之一
- **THEN** 系统返回参数验证失败的错误信息
#### Scenario: 记录个人特有字段
- **WHEN** 个人客户申请中包含 bizProof是否有经营佐证或 loanLoop循环功能字段
- **THEN** 系统正确保存这些字段的值
#### Scenario: 自动设置客户类型
- **WHEN** 通过个人客户发起接口创建流程
- **THEN** 系统自动将 custType 设置为"个人",无需客户端传入
#### Scenario: 自动生成业务方流水号
- **WHEN** 发起个人客户利率定价流程时
- **THEN** 系统使用时间戳自动生成唯一的业务方流水号
#### Scenario: 记录创建和更新信息
- **WHEN** 个人客户利率定价流程创建成功
- **THEN** 系统自动记录创建者、创建时间、更新者、更新时间
### Requirement: 个人客户发起接口字段定义
个人客户发起接口 SHALL 接受以下字段:
#### Scenario: 基本信息字段
- **WHEN** 客户端提交个人客户发起请求
- **THEN** 系统接受以下基本信息字段:
- `custIsn`(必填):客户内码
- `custName`:客户名称
- `idType`:证件类型
- `idNum`:证件号码
#### Scenario: 贷款信息字段
- **WHEN** 客户端提交个人客户发起请求
- **THEN** 系统接受以下贷款信息字段:
- `guarType`(必填):担保方式,可选值"信用"、"保证"、"抵押"、"质押"
- `applyAmt`(必填):申请金额,单位:元
#### Scenario: 个人特有字段
- **WHEN** 客户端提交个人客户发起请求
- **THEN** 系统接受以下个人特有字段:
- `bizProof`:是否有经营佐证(个人经营性贷款提供的经营佐证包括:借款人或其配偶为法定代表人、实际经营者、股东的企业(个体工商户)营业执照或企查查、企信宝查档资料)
- `loanLoop`:贷款合同是否开通循环功能
#### Scenario: 抵质押信息字段
- **WHEN** 客户端提交个人客户发起请求
- **THEN** 系统接受以下抵质押信息字段:
- `collType`:抵质押类型
- `collThirdParty`:抵质押物是否三方所有
## MODIFIED Requirements
### Requirement: 利率定价流程发起接口弃用策略
原有的统一发起接口 (`POST /loanPricing/workflow/create`) SHALL 标记为 Deprecated系统 SHALL
继续支持该接口以保证向后兼容,同时引导使用新的个人或企业专用接口。
#### Scenario: 原有接口向后兼容
- **WHEN** 客户端继续使用原有发起接口
- **THEN** 系统继续处理请求并返回正确结果,但建议迁移到新接口
#### Scenario: 原有接口标记为已弃用
- **WHEN** 开发人员查看 API 文档
- **THEN** 原有接口标记为 Deprecated引导使用新的个人或企业专用接口
## Cross-References
- 相关 Capability: `corporate-loan-pricing-creation`(企业客户利率定价流程发起)
- 修改自 Capability: `loan-pricing-workflow` 中的"利率定价流程发起"需求

View File

@@ -1,149 +0,0 @@
# Tasks: 拆分个人和企业利率定价发起接口
## 数据库变更任务
### 0. 数据库表结构更新
- [x] 执行数据库迁移脚本,添加缺失字段:
- `id_num` varchar(100) - 证件号码(个人和企业都需要)
- `loan_loop` varchar(10) - 循环功能(个人客户专用)
- `is_trade_construction` varchar(10) - 贸易和建筑业企业标识(企业客户专用)
- `is_green_loan` varchar(10) - 绿色贷款(企业客户专用)
- `is_tech_ent` varchar(10) - 科技型企业(企业客户专用)
- `loan_term` varchar(50) - 贷款期限(企业客户专用)
- [x] 更新 `LoanPricingWorkflow` Entity 类,添加对应的属性和字段映射注解
- [ ] 验证数据库变更是否成功执行(需手动执行 SQL 脚本)
### 0.1 创建数据库迁移脚本
- [x]`sql/` 目录下创建 `add_missing_fields.sql` 文件
- [x] 包含所有 ALTER TABLE 语句
- [x] 添加详细的注释说明每个字段的用途
## 后端实现任务
### 1. 创建 DTO 类
- [x] 创建 `PersonalLoanPricingCreateDTO.java`
- 添加共同字段custIsn、custName、idType、idNum、guarType、applyAmt、collType、collThirdParty
- 添加个人客户特有字段bizProof是否有经营佐证、loanLoop循环功能
- 添加共同字段验证注解custIsn、guarType、applyAmt 为必填
- 添加担保方式枚举验证
- [x] 创建 `CorporateLoanPricingCreateDTO.java`
- 添加共同字段custIsn、custName、idType、idNum、guarType、applyAmt、collType、collThirdParty
- 添加企业客户特有字段isAgriGuar省农担担保贷款、isGreenLoan绿色贷款、isTechEnt科技型企业、isTradeConstruction贸易和建筑业企业、loanTerm贷款期限
- 添加共同字段验证注解custIsn、guarType、applyAmt 为必填
- 添加担保方式枚举验证
### 2. 更新 Entity 类
- [x]`LoanPricingWorkflow.java` 中添加缺失的字段属性:
- `idNum` - 证件号码
- `loanLoop` - 循环功能
- `isTradeConstruction` - 贸易和建筑业企业标识
- `isGreenLoan` - 绿色贷款
- `isTechEnt` - 科技型企业
- `loanTerm` - 贷款期限
- [x] 为新字段添加 MyBatis Plus 字段映射注解(如果需要)
- [ ] 验证 Entity 类与数据库表字段映射正确(需执行 SQL 后验证)
### 3. 创建转换器工具类
- [x] 创建 `LoanPricingConverter.java`
- 实现 `toEntity(PersonalLoanPricingCreateDTO)` 方法
- 实现 `toEntity(CorporateLoanPricingCreateDTO)` 方法
- 确保自动设置 custType 为"个人"或"企业"
- 正确映射所有字段,包括新增的 idNum、loanLoop、isTradeConstruction、isGreenLoan、isTechEnt、loanTerm
### 4. 修改 Service 层
- [x]`ILoanPricingWorkflowService` 接口中添加:
- `createPersonalLoanPricing(PersonalLoanPricingCreateDTO dto)` 方法声明
- `createCorporateLoanPricing(CorporateLoanPricingCreateDTO dto)` 方法声明
- [x]`LoanPricingWorkflowServiceImpl` 中实现新方法:
- 实现 `createPersonalLoanPricing` 方法,调用转换器后复用现有逻辑
- 实现 `createCorporateLoanPricing` 方法,调用转换器后复用现有逻辑
### 5. 修改 Controller 层
- [x]`LoanPricingWorkflowController` 中添加:
- `POST /loanPricing/workflow/create/personal` 接口
- `POST /loanPricing/workflow/create/corporate` 接口
- [x] 添加 Swagger 注解,明确标注接口用途和字段说明
- [x] 保持原有接口不变,不做 @Deprecated 标记
### 6. 单元测试
- [ ] 创建 `PersonalLoanPricingCreateDTOTest.java` 测试类
- 测试必填字段验证custIsn、guarType、applyAmt
- 测试担保方式枚举验证(信用/保证/抵押/质押)
- 测试个人特有字段bizProof、loanLoop
- [ ] 创建 `CorporateLoanPricingCreateDTOTest.java` 测试类
- 测试必填字段验证custIsn、guarType、applyAmt
- 测试担保方式枚举验证(信用/保证/抵押/质押)
- 测试企业特有字段isAgriGuar、isGreenLoan、isTechEnt、isTradeConstruction、loanTerm
- [ ] 创建 `LoanPricingConverterTest.java` 测试类
- 测试个人 DTO 转 Entity 映射完整性
- 测试企业 DTO 转 Entity 映射完整性
- 验证 custType 自动设置正确
### 7. 集成测试与测试脚本
- [x] 生成 HTTP 测试脚本 `test_personal_create.http`
- 测试个人客户发起成功场景(完整必填字段)
- 测试缺少必填字段的失败场景
- 测试担保方式枚举验证失败场景
- 使用 `/login/test` 接口获取测试 token
- [x] 生成 HTTP 测试脚本 `test_corporate_create.http`
- 测试企业客户发起成功场景(完整必填字段)
- 测试缺少必填字段的失败场景
- 测试担保方式枚举验证失败场景
- 测试企业特有字段isAgriGuar、isGreenLoan、isTechEnt、loanTerm
- [x] 生成 HTTP 测试脚本 `test_backward_compatibility.http`
- 验证原有 `POST /loanPricing/workflow/create` 接口仍可正常工作
- [x] 生成 Shell 测试脚本 `test_personal_create.sh`
- 将 HTTP 测试脚本转换为 Shell 脚本格式
- 使用 curl 命令进行接口调用
- 包含颜色输出和测试结果统计
- [x] 生成 Shell 测试脚本 `test_corporate_create.sh`
- 将 HTTP 测试脚本转换为 Shell 脚本格式
- 使用 curl 命令进行接口调用
- 包含颜色输出和测试结果统计
- [x] 生成 Shell 测试脚本 `test_backward_compatibility.sh`
- 将 HTTP 测试脚本转换为 Shell 脚本格式
- 使用 curl 命令进行接口调用
- 包含颜色输出和测试结果统计
- [ ] 执行所有测试脚本并验证结果
- [ ] 生成测试报告到 `doc/` 目录
## 文档和部署
### 8. API 文档
- [ ] 更新 Swagger 文档,添加两个新接口的完整说明
- [ ] 生成并导出 API 文档到项目 doc 目录
### 9. 代码审查和合并
- [ ] 提交 Pull Request
- [ ] 通过代码审查
- [ ] 合并到主分支
## 依赖关系
- **数据库变更任务0必须最先执行**:所有后端开发依赖于数据库字段完成
- 任务 1-5 可以并行开发依赖任务0完成
- 任务 6-7 依赖任务 1-5 完成
- 任务 8-9 依赖所有前序任务完成
> **注:本次变更仅涉及后端,前端暂不修改**
## 验证检查点
1. **数据库字段完整性**确保所有新增字段idNum、loanLoop、isTradeConstruction、isGreenLoan、isTechEnt、loanTerm已添加到数据库表
2. **Entity 类映射正确性**:确保 Entity 类字段与数据库表字段一一对应
3. **DTO 验证**:确保所有必填字段有 `@NotBlank` 注解,枚举字段有正确的验证
4. **转换器正确性**:确保 DTO 到 Entity 的转换不丢失字段,包括新增字段
5. **API 路由**:确保新接口路径正确且可访问
6. **向后兼容**:确保原有接口继续工作
7. **API 文档**:确保 Swagger 文档正确显示所有接口的参数说明

View File

@@ -1,31 +0,0 @@
# Project Context
## Purpose
[Describe your project's purpose and goals]
## Tech Stack
- [List your primary technologies]
- [e.g., TypeScript, React, Node.js]
## Project Conventions
### Code Style
[Describe your code style preferences, formatting rules, and naming conventions]
### Architecture Patterns
[Document your architectural decisions and patterns]
### Testing Strategy
[Explain your testing approach and requirements]
### Git Workflow
[Describe your branching strategy and commit conventions]
## Domain Context
[Add domain-specific knowledge that AI assistants need to understand]
## Important Constraints
[List any technical, business, or regulatory constraints]
## External Dependencies
[Document key external services, APIs, or systems]

View File

@@ -1,92 +0,0 @@
# loan-pricing-workflow-ui Specification
## Purpose
TBD - created by archiving change add-loan-pricing-frontend. Update Purpose after archive.
## Requirements
### Requirement: 流程列表查询
系统 SHALL 提供利率定价流程列表查询页面,支持分页和多条件筛选,并支持创建新流程。
#### Scenario: 查询流程列表
- **WHEN** 用户已登录系统且具有 `loanPricing:workflow:list` 权限,访问"利率定价管理 > 流程列表"菜单
- **THEN** 系统显示利率定价流程列表页面,包含查询表单(客户名称模糊查询、创建者、机构号筛选)、搜索和重置按钮、新增按钮(带权限控制)、数据表格(业务方流水号、客户名称、客户类型、担保方式、申请金额、贷款利率、创建时间、创建者)、分页组件、操作列(包含"查看"按钮)
#### Scenario: 使用筛选条件查询
- **WHEN** 用户在流程列表页面输入客户名称或选择创建者/机构号,点击搜索按钮
- **THEN** 系统根据筛选条件查询并更新列表数据
#### Scenario: 重置筛选条件
- **WHEN** 用户已设置筛选条件,点击重置按钮
- **THEN** 系统清空所有筛选条件并重新查询全部数据
### Requirement: 流程详情查看
系统 SHALL 提供流程详情查看功能,以对话框形式展示完整的流程信息。
#### Scenario: 查看流程详情
- **WHEN** 用户在流程列表页面且具有 `loanPricing:workflow:query` 权限,点击列表中某条记录的"查看"按钮
- **THEN** 系统弹出详情对话框,展示完整的流程信息(基本信息:业务方流水号、机构编码、客户内码、客户名称、证件类型;业务信息:客户类型、担保方式、申请金额、贷款利率、贷款用途;业务标识:中间业务标识、企业标识;抵质押信息:抵质押类型、是否三方所有;其他信息:创建时间、创建者、更新时间、更新者)
### Requirement: 菜单和权限配置
系统 SHALL 在数据库中正确配置菜单项和权限,确保用户可以访问功能。
#### Scenario: 菜单显示和导航
- **WHEN** 用户已登录系统且具有利率定价流程相关权限
- **THEN** 系统在左侧菜单栏显示"利率定价管理"一级菜单,展开后显示"流程列表"二级菜单项
#### Scenario: 菜单路由配置
- **WHEN** 用户点击"流程列表"菜单项,系统处理路由跳转
- **THEN** 系统导航至 `/loanPricing/workflow` 路径,加载对应的前端组件
### Requirement: API 接口集成
前端 SHALL 正确调用后端 API 接口获取数据和提交创建请求。
#### Scenario: 列表接口调用
- **WHEN** 用户访问流程列表页面,页面初始化或用户执行查询操作
- **THEN** 前端调用 `GET /loanPricing/workflow/list` 接口,传入分页和筛选参数
#### Scenario: 详情接口调用
- **WHEN** 用户点击查看按钮,前端获取选中记录的业务方流水号
- **THEN** 前端调用 `GET /loanPricing/workflow/{serialNum}` 接口获取详情数据
#### Scenario: 创建接口调用
- **WHEN** 用户填写完创建表单并点击确定按钮
- **THEN** 前端调用 `POST /loanPricing/workflow/create` 接口,传入表单数据,成功后关闭对话框并刷新列表
### Requirement: 流程创建
系统 SHALL 提供创建新利率定价流程的功能,通过表单对话框收集必要信息。
#### Scenario: 打开创建表单
- **WHEN** 用户在流程列表页面且具有 `loanPricing:workflow:create` 权限,点击"新增"按钮
- **THEN** 系统弹出创建流程表单对话框,显示所有必填和可选字段
#### Scenario: 表单字段显示
- **WHEN** 用户打开创建流程表单对话框
- **THEN** 系统显示以下字段分组:
- 基本信息:客户内码(必填)、客户名称、客户类型(必填,下拉选择:个人/企业)、证件类型
- 贷款信息:申请金额(必填)、贷款利率(必填)、担保方式(必填,下拉选择:信用/保证/抵押/质押、贷款用途下拉选择consumer/business
- 中间业务标识(个人):个人快捷支付(开关)、个人电费代扣(开关)
- 中间业务标识(企业):企业电费代扣(开关)、企业水费代扣(开关)
- 企业标识净身企业开关、开立基本结算账户开关、制造业企业开关、省农担担保贷款开关、纳税信用等级A级开关、县级及以上农业龙头企业开关、普惠小微借款人开关
- 抵质押信息:抵质押类型(下拉选择:一线/一类/二类)、抵质押物三方所有(开关)、是否有经营佐证(开关)
- 固定字段机构编码隐藏固定值931000、运行模式隐藏固定值1
#### Scenario: 表单验证
- **WHEN** 用户填写表单并点击确定按钮
- **THEN** 系统验证必填字段:客户内码、客户类型、担保方式、申请金额、贷款利率,如有缺失则显示错误提示
#### Scenario: 提交创建成功
- **WHEN** 用户填写完必填字段并点击确定按钮,后端返回成功响应
- **THEN** 系统关闭对话框,显示成功提示消息,刷新列表数据
#### Scenario: 取消创建
- **WHEN** 用户点击取消按钮或对话框关闭按钮
- **THEN** 系统关闭对话框,不保存数据,不刷新列表
#### Scenario: 新增按钮权限控制
- **WHEN** 用户不具有 `loanPricing:workflow:create` 权限
- **THEN** 系统不显示"新增"按钮

View File

@@ -1,77 +0,0 @@
# loan-pricing-workflow Specification
## Purpose
TBD - created by archiving change add-loan-pricing-workflow. Update Purpose after archive.
## Requirements
### Requirement: 利率定价流程发起
系统 SHALL 提供利率定价流程发起接口,允许业务人员创建新的利率定价申请。
#### Scenario: 成功发起利率定价流程
- **WHEN** 业务人员提交包含必填字段(custIsn、custType、guarType、applyAmt、loanRate)的完整申请
- **THEN** 系统自动生成业务方流水号(serialNum)并保存记录,返回成功响应
#### Scenario: 自动生成业务方流水号
- **WHEN** 发起利率定价流程时
- **THEN** 系统使用时间戳自动生成唯一的业务方流水号,无需用户输入
#### Scenario: 记录创建和更新信息
- **WHEN** 利率定价流程创建成功
- **THEN** 系统自动记录创建者、创建时间、更新者、更新时间
#### Scenario: 字段验证-必填字段
- **WHEN** 提交的申请缺少必填字段(custIsn、custType、guarType、applyAmt、loanRate)
- **THEN** 系统返回参数验证失败的错误信息
#### Scenario: 字段验证-固定值字段
- **WHEN** 提交的申请中 orgCode 非 "931000" 或 runType 非 "1"
- **THEN** 系统返回参数验证失败的错误信息
#### Scenario: 字段验证-枚举值
- **WHEN** 提交的申请中 custType 不是"个人"或"企业"
- **THEN** 系统返回参数验证失败的错误信息
#### Scenario: 字段验证-担保方式
- **WHEN** 提交的申请中 guarType 不是"信用"、"保证"、"抵押"、"质押"之一
- **THEN** 系统返回参数验证失败的错误信息
### Requirement: 利率定价流程列表查询
系统 SHALL 提供利率定价流程列表查询接口,支持分页和多条件筛选。
#### Scenario: 默认按更新时间倒序排列
- **WHEN** 业务人员查询利率定价流程列表
- **THEN** 结果按更新时间(update_time)倒序排列
#### Scenario: 支持分页查询
- **WHEN** 业务人员指定页码和每页数量查询列表
- **THEN** 系统返回对应页的数据及总记录数
#### Scenario: 按创建者筛选
- **WHEN** 业务人员按创建者筛选查询
- **THEN** 系统返回该创建者创建的利率定价流程记录
#### Scenario: 按客户名称筛选
- **WHEN** 业务人员按客户名称(custName)模糊查询
- **THEN** 系统返回客户名称包含查询条件的记录
#### Scenario: 按机构号筛选
- **WHEN** 业务人员按机构号(orgCode)筛选查询
- **THEN** 系统返回该机构号的利率定价流程记录
#### Scenario: 组合条件筛选
- **WHEN** 业务人员同时指定多个筛选条件
- **THEN** 系统返回同时满足所有条件的记录
### Requirement: 利率定价流程详情查询
系统 SHALL 提供根据业务方流水号查询流程详情的接口。
#### Scenario: 根据业务方流水号查询详情
- **WHEN** 业务人员提供有效的业务方流水号(serialNum)
- **THEN** 系统返回该流程的所有字段信息
#### Scenario: 查询不存在的流水号
- **WHEN** 业务人员查询的业务方流水号不存在
- **THEN** 系统返回"记录不存在"的错误信息

View File

@@ -1,307 +0,0 @@
#!/bin/bash
# 利率定价流程 API 完整测试脚本 (修复编码问题)
# 自动登录获取 token 并执行所有测试用例
BASE_URL="http://localhost:8080"
TOKEN=""
# 颜色定义
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 测试结果统计
TOTAL_TESTS=0
PASSED_TESTS=0
FAILED_TESTS=0
# 测试结果记录
declare -a TEST_RESULTS
echo -e "${BLUE}====================================${NC}"
echo -e "${BLUE} 利率定价流程 API 测试套件${NC}"
echo -e "${BLUE}====================================${NC}"
echo ""
# 步骤 1: 获取 Token
echo -e "${YELLOW}[步骤 1] 获取测试 Token${NC}"
echo "-----------------------------------"
LOGIN_RESPONSE=$(curl -s -X POST "$BASE_URL/login/test" \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin123"}')
# 解析 token
TOKEN=$(echo "$LOGIN_RESPONSE" | grep -o '"token":"[^"]*"' | cut -d'"' -f4)
if [ -z "$TOKEN" ]; then
echo -e "${RED}✗ 登录失败,无法获取 token${NC}"
echo "响应: $LOGIN_RESPONSE"
exit 1
fi
echo -e "${GREEN}✓ 登录成功${NC}"
echo "Token: ${TOKEN:0:50}..."
echo ""
# 测试函数
test_api() {
local method=$1
local url=$2
local data=$3
local description=$4
local expected_code=${5:-200}
TOTAL_TESTS=$((TOTAL_TESTS + 1))
echo -n "[$TOTAL_TESTS] 测试: $description ... "
if [ "$method" = "GET" ]; then
response=$(curl -s -X GET "$BASE_URL$url" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json")
else
# 使用 --data-urlencode 或直接从文件读取来避免编码问题
response=$(curl -s -X "$method" "$BASE_URL$url" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json; charset=utf-8" \
--data-raw "$data")
fi
# 检查响应
actual_code=$(echo "$response" | grep -o '"code":[0-9]*' | cut -d':' -f2)
if [ "$actual_code" = "$expected_code" ]; then
echo -e "${GREEN}✓ 通过${NC}"
PASSED_TESTS=$((PASSED_TESTS + 1))
TEST_RESULTS+=("$description")
else
echo -e "${RED}✗ 失败 (期望: $expected_code, 实际: $actual_code)${NC}"
FAILED_TESTS=$((FAILED_TESTS + 1))
TEST_RESULTS+=("$description - 期望码: $expected_code, 实际: $actual_code")
echo " 响应: $response"
fi
}
# 步骤 2: 执行测试用例
echo -e "${YELLOW}[步骤 2] 执行测试用例${NC}"
echo "-----------------------------------"
echo ""
# ====== 功能测试 ======
echo -e "${BLUE}【功能测试】${NC}"
# 测试 1: 发起利率定价流程 - 个人客户信用贷款
# 使用 printf 来确保 UTF-8 编码
JSON_DATA_1=$(cat << 'EOF'
{
"orgCode": "931000",
"runType": "1",
"custIsn": "CUST20250119001",
"custType": "个人",
"guarType": "信用",
"midPerQuickPay": "true",
"midPerEleDdc": "false",
"midEntEleDdc": "false",
"midEntWaterDdc": "false",
"applyAmt": "50000",
"isCleanEnt": "false",
"hasSettleAcct": "true",
"isManufacturing": "false",
"isAgriGuar": "false",
"isTaxA": "false",
"isAgriLeading": "false",
"loanPurpose": "consumer",
"bizProof": "true",
"collType": "一类",
"collThirdParty": "false",
"loanRate": "4.35",
"custName": "张三",
"idType": "身份证",
"isInclusiveFinance": "true"
}
EOF
)
test_api "POST" "/loanPricing/workflow/create" "$JSON_DATA_1" "发起流程-个人客户信用贷款"
# 测试 2: 发起利率定价流程 - 企业客户抵押贷款
JSON_DATA_2=$(cat << 'EOF'
{
"orgCode": "931000",
"runType": "1",
"custIsn": "CUST20250119002",
"custType": "企业",
"guarType": "抵押",
"applyAmt": "500000",
"isCleanEnt": "true",
"hasSettleAcct": "true",
"isManufacturing": "true",
"isTaxA": "true",
"loanPurpose": "business",
"collType": "一线",
"collThirdParty": "false",
"loanRate": "3.85",
"custName": "测试科技有限公司",
"idType": "统一社会信用代码",
"isInclusiveFinance": "true"
}
EOF
)
test_api "POST" "/loanPricing/workflow/create" "$JSON_DATA_2" "发起流程-企业客户抵押贷款"
# 测试 3: 发起利率定价流程 - 农业担保贷款
JSON_DATA_3=$(cat << 'EOF'
{
"orgCode": "931000",
"runType": "1",
"custIsn": "CUST20250119003",
"custType": "企业",
"guarType": "保证",
"applyAmt": "300000",
"isAgriGuar": "true",
"isAgriLeading": "true",
"loanPurpose": "business",
"loanRate": "4.15",
"custName": "绿源农业合作社",
"idType": "统一社会信用代码",
"isInclusiveFinance": "true"
}
EOF
)
test_api "POST" "/loanPricing/workflow/create" "$JSON_DATA_3" "发起流程-农业担保贷款"
# 测试 4: 发起利率定价流程 - 质押贷款
JSON_DATA_4=$(cat << 'EOF'
{
"orgCode": "931000",
"runType": "1",
"custIsn": "CUST20250119004",
"custType": "个人",
"guarType": "质押",
"applyAmt": "100000",
"loanPurpose": "consumer",
"collType": "二类",
"loanRate": "4.25",
"custName": "李四",
"idType": "身份证",
"isInclusiveFinance": "false"
}
EOF
)
test_api "POST" "/loanPricing/workflow/create" "$JSON_DATA_4" "发起流程-个人客户质押贷款"
# 测试 5: 查询流程列表 - 默认分页
test_api "GET" "/loanPricing/workflow/list?pageNum=1&pageSize=10" "" "查询流程列表-默认分页"
# ====== 异常测试 ======
echo ""
echo -e "${BLUE}【异常测试】${NC}"
# 测试 11: 必填字段缺失 - 客户内码为空
JSON_DATA_ERR1=$(cat << 'EOF'
{
"custType": "个人",
"guarType": "信用",
"applyAmt": "50000",
"loanRate": "4.35"
}
EOF
)
test_api "POST" "/loanPricing/workflow/create" "$JSON_DATA_ERR1" "异常测试-客户内码为空" 500
# 测试 12: 必填字段缺失 - 贷款利率为空
JSON_DATA_ERR2=$(cat << 'EOF'
{
"custIsn": "TEST001",
"custType": "个人",
"guarType": "信用",
"applyAmt": "50000"
}
EOF
)
test_api "POST" "/loanPricing/workflow/create" "$JSON_DATA_ERR2" "异常测试-贷款利率为空" 500
# 测试 13: 查询不存在的流程
test_api "GET" "/loanPricing/workflow/NOTEXIST123" "" "异常测试-查询不存在的流程" 500
# 步骤 3: 生成测试报告
echo ""
echo -e "${YELLOW}[步骤 3] 测试结果统计${NC}"
echo "-----------------------------------"
echo ""
# 计算通过率
if [ $TOTAL_TESTS -gt 0 ]; then
PASS_RATE=$((PASSED_TESTS * 100 / TOTAL_TESTS))
else
PASS_RATE=0
fi
echo "总测试数: $TOTAL_TESTS"
echo -e "通过: ${GREEN}$PASSED_TESTS${NC}"
echo -e "失败: ${RED}$FAILED_TESTS${NC}"
echo "通过率: $PASS_RATE%"
echo ""
# 详细结果
echo "详细测试结果:"
echo "-----------------------------------"
for result in "${TEST_RESULTS[@]}"; do
if [[ $result == ✓* ]]; then
echo -e "${GREEN}$result${NC}"
else
echo -e "${RED}$result${NC}"
fi
done
echo ""
# 生成测试报告文件
REPORT_FILE="api-test-report-$(date +%Y%m%d%H%M%S).txt"
echo "生成测试报告: $REPORT_FILE"
cat > "$REPORT_FILE" << EOF
利率定价流程 API 测试报告
====================================
测试时间: $(date '+%Y-%m-%d %H:%M:%S')
测试环境: $BASE_URL
测试账号: admin
测试统计
--------
总测试数: $TOTAL_TESTS
通过数: $PASSED_TESTS
失败数: $FAILED_TESTS
通过率: $PASS_RATE%
测试用例详情
--------
EOF
for result in "${TEST_RESULTS[@]}"; do
echo "$result" >> "$REPORT_FILE"
done
echo "" >> "$REPORT_FILE"
echo "====================================" >> "$REPORT_FILE"
echo "测试结束" >> "$REPORT_FILE"
echo ""
echo -e "${BLUE}====================================${NC}"
echo -e "${BLUE} 测试完成${NC}"
echo -e "${BLUE}====================================${NC}"
echo "测试报告已保存到: $REPORT_FILE"
# 返回退出码
if [ $FAILED_TESTS -gt 0 ]; then
exit 1
else
exit 0
fi

View File

@@ -1,262 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
利率定价流程 API 测试脚本
使用 Python 避免 Windows 环境下的编码问题
"""
import requests
import json
from datetime import datetime
BASE_URL = "http://localhost:8080"
TOKEN = ""
# 颜色代码
class Colors:
GREEN = '\033[0;32m'
RED = '\033[0;31m'
YELLOW = '\033[1;33m'
BLUE = '\033[0;34m'
NC = '\033[0m'
def print_header(text):
print(f"{Colors.BLUE}{'='*40}{Colors.NC}")
print(f"{Colors.BLUE}{text:^40}{Colors.NC}")
print(f"{Colors.BLUE}{'='*40}{Colors.NC}")
print()
def get_token():
"""获取测试 Token"""
print(f"{Colors.YELLOW}[步骤 1] 获取测试 Token{Colors.NC}")
print("-" * 35)
response = requests.post(
f"{BASE_URL}/login/test",
json={"username": "admin", "password": "admin123"}
)
result = response.json()
if result.get("code") == 200:
token = result.get("token")
print(f"{Colors.GREEN}✓ 登录成功{Colors.NC}")
print(f"Token: {token[:50]}...")
print()
return token
else:
print(f"{Colors.RED}✗ 登录失败{Colors.NC}")
print(f"响应: {result}")
exit(1)
def test_api(method, url, data, description, expected_code=200):
"""执行 API 测试"""
global TOTAL_TESTS, PASSED_TESTS, FAILED_TESTS, TEST_RESULTS
TOTAL_TESTS += 1
print(f"[{TOTAL_TESTS}] 测试: {description} ... ", end="", flush=True)
headers = {
"Authorization": f"Bearer {TOKEN}",
"Content-Type": "application/json; charset=utf-8"
}
try:
if method == "GET":
response = requests.get(f"{BASE_URL}{url}", headers=headers)
else:
response = requests.post(f"{BASE_URL}{url}", headers=headers, json=data)
result = response.json()
actual_code = result.get("code")
if actual_code == expected_code:
print(f"{Colors.GREEN}✓ 通过{Colors.NC}")
PASSED_TESTS += 1
TEST_RESULTS.append(f"{description}")
else:
print(f"{Colors.RED}✗ 失败 (期望: {expected_code}, 实际: {actual_code}){Colors.NC}")
FAILED_TESTS += 1
TEST_RESULTS.append(f"{description} - 期望码: {expected_code}, 实际: {actual_code}")
print(f" 响应: {json.dumps(result, ensure_ascii=False)[:200]}")
except Exception as e:
print(f"{Colors.RED}✗ 异常: {str(e)}{Colors.NC}")
FAILED_TESTS += 1
TEST_RESULTS.append(f"{description} - 异常: {str(e)}")
def main():
global TOTAL_TESTS, PASSED_TESTS, FAILED_TESTS, TEST_RESULTS
TOTAL_TESTS = 0
PASSED_TESTS = 0
FAILED_TESTS = 0
TEST_RESULTS = []
print_header("利率定价流程 API 测试套件")
# 获取 Token
TOKEN = get_token()
# 执行测试
print(f"{Colors.YELLOW}[步骤 2] 执行测试用例{Colors.NC}")
print("-" * 35)
print()
print(f"{Colors.BLUE}【功能测试】{Colors.NC}")
# 测试 1: 个人客户信用贷款
test_api("POST", "/loanPricing/workflow/create", {
"orgCode": "931000",
"runType": "1",
"custIsn": "CUST20250119001",
"custType": "个人",
"guarType": "信用",
"midPerQuickPay": "true",
"midPerEleDdc": "false",
"midEntEleDdc": "false",
"midEntWaterDdc": "false",
"applyAmt": "50000",
"isCleanEnt": "false",
"hasSettleAcct": "true",
"isManufacturing": "false",
"isAgriGuar": "false",
"isTaxA": "false",
"isAgriLeading": "false",
"loanPurpose": "consumer",
"bizProof": "true",
"collType": "一类",
"collThirdParty": "false",
"loanRate": "4.35",
"custName": "张三",
"idType": "身份证",
"isInclusiveFinance": "true"
}, "发起流程-个人客户信用贷款")
# 测试 2: 企业客户抵押贷款
test_api("POST", "/loanPricing/workflow/create", {
"orgCode": "931000",
"runType": "1",
"custIsn": "CUST20250119002",
"custType": "企业",
"guarType": "抵押",
"applyAmt": "500000",
"isCleanEnt": "true",
"hasSettleAcct": "true",
"isManufacturing": "true",
"isTaxA": "true",
"loanPurpose": "business",
"collType": "一线",
"collThirdParty": "false",
"loanRate": "3.85",
"custName": "测试科技有限公司",
"idType": "统一社会信用代码",
"isInclusiveFinance": "true"
}, "发起流程-企业客户抵押贷款")
# 测试 3: 农业担保贷款
test_api("POST", "/loanPricing/workflow/create", {
"orgCode": "931000",
"runType": "1",
"custIsn": "CUST20250119003",
"custType": "企业",
"guarType": "保证",
"applyAmt": "300000",
"isAgriGuar": "true",
"isAgriLeading": "true",
"loanPurpose": "business",
"loanRate": "4.15",
"custName": "绿源农业合作社",
"idType": "统一社会信用代码",
"isInclusiveFinance": "true"
}, "发起流程-农业担保贷款")
# 测试 4: 个人质押贷款
test_api("POST", "/loanPricing/workflow/create", {
"orgCode": "931000",
"runType": "1",
"custIsn": "CUST20250119004",
"custType": "个人",
"guarType": "质押",
"applyAmt": "100000",
"loanPurpose": "consumer",
"collType": "二类",
"loanRate": "4.25",
"custName": "李四",
"idType": "身份证",
"isInclusiveFinance": "false"
}, "发起流程-个人客户质押贷款")
# 测试 5: 查询列表
test_api("GET", "/loanPricing/workflow/list?pageNum=1&pageSize=10", None, "查询流程列表-默认分页")
print()
print(f"{Colors.BLUE}【异常测试】{Colors.NC}")
# 测试 11: 客户内码为空
test_api("POST", "/loanPricing/workflow/create", {
"custType": "个人",
"guarType": "信用",
"applyAmt": "50000",
"loanRate": "4.35"
}, "异常测试-客户内码为空", 500)
# 测试 12: 贷款利率为空
test_api("POST", "/loanPricing/workflow/create", {
"custIsn": "TEST001",
"custType": "个人",
"guarType": "信用",
"applyAmt": "50000"
}, "异常测试-贷款利率为空", 500)
# 测试 13: 查询不存在的流程
test_api("GET", "/loanPricing/workflow/NOTEXIST123", None, "异常测试-查询不存在的流程", 500)
# 生成报告
print()
print(f"{Colors.YELLOW}[步骤 3] 测试结果统计{Colors.NC}")
print("-" * 35)
print()
pass_rate = int(PASSED_TESTS * 100 / TOTAL_TESTS) if TOTAL_TESTS > 0 else 0
print(f"总测试数: {TOTAL_TESTS}")
print(f"通过: {Colors.GREEN}{PASSED_TESTS}{Colors.NC}")
print(f"失败: {Colors.RED}{FAILED_TESTS}{Colors.NC}")
print(f"通过率: {pass_rate}%")
print()
print("详细测试结果:")
print("-" * 35)
for result in TEST_RESULTS:
if result.startswith(""):
print(f"{Colors.GREEN}{result}{Colors.NC}")
else:
print(f"{Colors.RED}{result}{Colors.NC}")
# 保存报告
report_file = f"api-test-report-{datetime.now().strftime('%Y%m%d%H%M%S')}.txt"
with open(report_file, "w", encoding="utf-8") as f:
f.write("利率定价流程 API 测试报告\n")
f.write("=" * 36 + "\n\n")
f.write(f"测试时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
f.write(f"测试环境: {BASE_URL}\n")
f.write(f"测试账号: admin\n\n")
f.write("测试统计\n")
f.write("-" * 10 + "\n")
f.write(f"总测试数: {TOTAL_TESTS}\n")
f.write(f"通过数: {PASSED_TESTS}\n")
f.write(f"失败数: {FAILED_TESTS}\n")
f.write(f"通过率: {pass_rate}%\n\n")
f.write("测试用例详情\n")
f.write("-" * 14 + "\n")
for result in TEST_RESULTS:
f.write(result + "\n")
print()
print(f"测试报告已保存到: {report_file}")
print_header("测试完成")
return 0 if FAILED_TESTS == 0 else 1
if __name__ == "__main__":
exit(main())

View File

@@ -1,290 +0,0 @@
#!/bin/bash
# 利率定价流程 API 完整测试脚本
# 自动登录获取 token 并执行所有测试用例
BASE_URL="http://localhost:8080"
TOKEN=""
# 颜色定义
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 测试结果统计
TOTAL_TESTS=0
PASSED_TESTS=0
FAILED_TESTS=0
# 测试结果记录
declare -a TEST_RESULTS
echo -e "${BLUE}====================================${NC}"
echo -e "${BLUE} 利率定价流程 API 测试套件${NC}"
echo -e "${BLUE}====================================${NC}"
echo ""
# 步骤 1: 获取 Token
echo -e "${YELLOW}[步骤 1] 获取测试 Token${NC}"
echo "-----------------------------------"
LOGIN_RESPONSE=$(curl -s -X POST "$BASE_URL/login/test" \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin123"}')
# 解析 token
TOKEN=$(echo "$LOGIN_RESPONSE" | grep -o '"token":"[^"]*"' | cut -d'"' -f4)
if [ -z "$TOKEN" ]; then
echo -e "${RED}✗ 登录失败,无法获取 token${NC}"
echo "响应: $LOGIN_RESPONSE"
exit 1
fi
echo -e "${GREEN}✓ 登录成功${NC}"
echo "Token: ${TOKEN:0:50}..."
echo ""
# 测试函数
test_api() {
local method=$1
local url=$2
local data=$3
local description=$4
local expected_code=${5:-200}
TOTAL_TESTS=$((TOTAL_TESTS + 1))
echo -n "[$TOTAL_TESTS] 测试: $description ... "
if [ "$method" = "GET" ]; then
response=$(curl -s -X GET "$BASE_URL$url" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json")
else
response=$(curl -s -X "$method" "$BASE_URL$url" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "$data")
fi
# 检查响应
actual_code=$(echo "$response" | grep -o '"code":[0-9]*' | cut -d':' -f2)
if [ "$actual_code" = "$expected_code" ]; then
echo -e "${GREEN}✓ 通过${NC}"
PASSED_TESTS=$((PASSED_TESTS + 1))
TEST_RESULTS+=("$description")
else
echo -e "${RED}✗ 失败 (期望: $expected_code, 实际: $actual_code)${NC}"
FAILED_TESTS=$((FAILED_TESTS + 1))
TEST_RESULTS+=("$description - 期望码: $expected_code, 实际: $actual_code")
echo " 响应: $response"
fi
}
# 步骤 2: 执行测试用例
echo -e "${YELLOW}[步骤 2] 执行测试用例${NC}"
echo "-----------------------------------"
echo ""
# ====== 功能测试 ======
echo -e "${BLUE}【功能测试】${NC}"
# 测试 1: 发起利率定价流程 - 个人客户信用贷款
test_api "POST" "/loanPricing/workflow/create" '{
"orgCode": "931000",
"runType": "1",
"custIsn": "CUST20250119001",
"custType": "个人",
"guarType": "信用",
"midPerQuickPay": "true",
"midPerEleDdc": "false",
"midEntEleDdc": "false",
"midEntWaterDdc": "false",
"applyAmt": "50000",
"isCleanEnt": "false",
"hasSettleAcct": "true",
"isManufacturing": "false",
"isAgriGuar": "false",
"isTaxA": "false",
"isAgriLeading": "false",
"loanPurpose": "consumer",
"bizProof": "true",
"collType": "一类",
"collThirdParty": "false",
"loanRate": "4.35",
"custName": "张三",
"idType": "身份证",
"isInclusiveFinance": "true"
}' "发起流程-个人客户信用贷款"
# 测试 2: 发起利率定价流程 - 企业客户抵押贷款
test_api "POST" "/loanPricing/workflow/create" '{
"orgCode": "931000",
"runType": "1",
"custIsn": "CUST20250119002",
"custType": "企业",
"guarType": "抵押",
"applyAmt": "500000",
"isCleanEnt": "true",
"hasSettleAcct": "true",
"isManufacturing": "true",
"isTaxA": "true",
"loanPurpose": "business",
"collType": "一线",
"collThirdParty": "false",
"loanRate": "3.85",
"custName": "测试科技有限公司",
"idType": "统一社会信用代码",
"isInclusiveFinance": "true"
}' "发起流程-企业客户抵押贷款"
# 测试 3: 发起利率定价流程 - 农业担保贷款
test_api "POST" "/loanPricing/workflow/create" '{
"orgCode": "931000",
"runType": "1",
"custIsn": "CUST20250119003",
"custType": "企业",
"guarType": "保证",
"applyAmt": "300000",
"isAgriGuar": "true",
"isAgriLeading": "true",
"loanPurpose": "business",
"loanRate": "4.15",
"custName": "绿源农业合作社",
"idType": "统一社会信用代码",
"isInclusiveFinance": "true"
}' "发起流程-农业担保贷款"
# 测试 4: 发起利率定价流程 - 质押贷款
test_api "POST" "/loanPricing/workflow/create" '{
"orgCode": "931000",
"runType": "1",
"custIsn": "CUST20250119004",
"custType": "个人",
"guarType": "质押",
"applyAmt": "100000",
"loanPurpose": "consumer",
"collType": "二类",
"loanRate": "4.25",
"custName": "李四",
"idType": "身份证",
"isInclusiveFinance": "false"
}' "发起流程-个人客户质押贷款"
# 测试 5: 查询流程列表 - 默认分页
test_api "GET" "/loanPricing/workflow/list?pageNum=1&pageSize=10" "" "查询流程列表-默认分页"
# 测试 6: 查询流程列表 - 筛选个人客户
test_api "GET" "/loanPricing/workflow/list?pageNum=1&pageSize=10&custType=个人" "" "查询流程列表-筛选个人客户"
# 测试 7: 查询流程列表 - 筛选企业客户
test_api "GET" "/loanPricing/workflow/list?pageNum=1&pageSize=10&custType=企业" "" "查询流程列表-筛选企业客户"
# 测试 8: 查询流程列表 - 按客户名称搜索
test_api "GET" "/loanPricing/workflow/list?pageNum=1&pageSize=10&custName=张三" "" "查询流程列表-搜索张三"
# 测试 9: 查询流程列表 - 按担保方式筛选
test_api "GET" "/loanPricing/workflow/list?pageNum=1&pageSize=10&guarType=信用" "" "查询流程列表-筛选信用贷款"
# 测试 10: 查询流程详情
test_api "GET" "/loanPricing/workflow/CUST20250119001" "" "查询流程详情-CUST20250119001"
# ====== 异常测试 ======
echo ""
echo -e "${BLUE}【异常测试】${NC}"
# 测试 11: 必填字段缺失 - 客户内码为空
test_api "POST" "/loanPricing/workflow/create" '{
"custType": "个人",
"guarType": "信用",
"applyAmt": "50000",
"loanRate": "4.35"
}' "异常测试-客户内码为空" 500
# 测试 12: 必填字段缺失 - 贷款利率为空
test_api "POST" "/loanPricing/workflow/create" '{
"custIsn": "TEST001",
"custType": "个人",
"guarType": "信用",
"applyAmt": "50000"
}' "异常测试-贷款利率为空" 500
# 测试 13: 查询不存在的流程
test_api "GET" "/loanPricing/workflow/NOTEXIST123" "" "异常测试-查询不存在的流程" 500
# 步骤 3: 生成测试报告
echo ""
echo -e "${YELLOW}[步骤 3] 测试结果统计${NC}"
echo "-----------------------------------"
echo ""
# 计算通过率
if [ $TOTAL_TESTS -gt 0 ]; then
PASS_RATE=$((PASSED_TESTS * 100 / TOTAL_TESTS))
else
PASS_RATE=0
fi
echo "总测试数: $TOTAL_TESTS"
echo -e "通过: ${GREEN}$PASSED_TESTS${NC}"
echo -e "失败: ${RED}$FAILED_TESTS${NC}"
echo "通过率: $PASS_RATE%"
echo ""
# 详细结果
echo "详细测试结果:"
echo "-----------------------------------"
for result in "${TEST_RESULTS[@]}"; do
if [[ $result == ✓* ]]; then
echo -e "${GREEN}$result${NC}"
else
echo -e "${RED}$result${NC}"
fi
done
echo ""
# 生成测试报告文件
REPORT_FILE="api-test-report-$(date +%Y%m%d%H%M%S).txt"
echo "生成测试报告: $REPORT_FILE"
cat > "$REPORT_FILE" << EOF
利率定价流程 API 测试报告
====================================
测试时间: $(date '+%Y-%m-%d %H:%M:%S')
测试环境: $BASE_URL
测试账号: admin
测试统计
--------
总测试数: $TOTAL_TESTS
通过数: $PASSED_TESTS
失败数: $FAILED_TESTS
通过率: $PASS_RATE%
测试用例详情
--------
EOF
for result in "${TEST_RESULTS[@]}"; do
echo "$result" >> "$REPORT_FILE"
done
echo "" >> "$REPORT_FILE"
echo "====================================" >> "$REPORT_FILE"
echo "测试结束" >> "$REPORT_FILE"
echo ""
echo -e "${BLUE}====================================${NC}"
echo -e "${BLUE} 测试完成${NC}"
echo -e "${BLUE}====================================${NC}"
echo "测试报告已保存到: $REPORT_FILE"
# 返回退出码
if [ $FAILED_TESTS -gt 0 ]; then
exit 1
else
exit 0
fi

View File

@@ -25,7 +25,7 @@ spring:
druid:
# 主库数据源
master:
url: jdbc:mysql://116.62.17.81:3306/loan-pricing?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
url: jdbc:mysql://116.62.17.81:3307/loan-pricing?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: Kfcx@1234
# 从库数据源
@@ -102,4 +102,4 @@ spring:
# #连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms
model:
url: http://localhost:8080/rate/pricing/mock/invokeModel
url: http://localhost:8080/rate/pricing/mock/invokeModel

View File

@@ -7,7 +7,7 @@ ruoyi:
# 版权年份
copyrightYear: 2026
# 文件路径 示例( Windows配置D:/ruoyi/uploadPathLinux配置 /home/ruoyi/uploadPath
profile: D:/ruoyi/uploadPath
profile: uploadPath
# 获取ip地址开关
addressEnabled: false
# 验证码类型 math 数字计算 char 字符验证

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 日志存放路径 -->
<property name="log.path" value="/home/ruoyi/logs" />
<property name="log.path" value="logs" />
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />

View File

@@ -0,0 +1,373 @@
-- 说明:
-- 1. 本文件从源库 116.62.17.81:3306/loan-pricing 以 utf8mb4 正确导出
-- 2. 本文件仅包含迁移后系统可运行所需的基础配置数据和当前业务关键数据
-- 3. 已包含的表: loan_pricing_workflow, model_corp_output_fields, model_retail_output_fields,
-- sys_config, sys_dept, sys_dict_data, sys_dict_type, sys_job, sys_menu, sys_notice,
-- sys_post, sys_role, sys_role_dept, sys_role_menu, sys_user, sys_user_post, sys_user_role
-- 4. 未包含日志和运行态数据: sys_job_log, sys_logininfor, sys_oper_log, QRTZ_* 运行态表
-- 5. 建议先执行表结构 SQL, 再执行本文件
SET NAMES utf8mb4;
USE `loan-pricing`;
SET FOREIGN_KEY_CHECKS=0;
DELETE FROM `loan_pricing_workflow`;
INSERT INTO `loan_pricing_workflow` (`id`, `serial_num`, `model_output_id`, `org_code`, `run_type`, `cust_isn`, `cust_type`, `guar_type`, `mid_per_quick_pay`, `mid_per_ele_ddc`, `mid_ent_ele_ddc`, `mid_ent_water_ddc`, `apply_amt`, `loan_term`, `is_clean_ent`, `has_settle_acct`, `is_manufacturing`, `is_agri_guar`, `is_tech_ent`, `is_green_loan`, `is_trade_construction`, `is_tax_a`, `is_agri_leading`, `loan_purpose`, `biz_proof`, `loan_loop`, `coll_type`, `coll_third_party`, `loan_rate`, `execute_rate`, `cust_name`, `id_type`, `id_num`, `is_inclusive_finance`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES
(1, '20260130160640382', 1, '892000', '1', '1234', '个人', '信用', 'false', 'false', 'false', 'false', '10000000', NULL, 'false', 'false', 'false', 'false', NULL, NULL, NULL, 'false', 'false', NULL, 'false', NULL, NULL, 'false', '11', NULL, NULL, '身份证', NULL, 'false', '若依-admin', '2026-01-30 16:06:40', '若依-admin', '2026-01-30 16:06:41'),
(2, '20260130163824202', 1, '892000', '1', '82821892198', '企业', '保证', 'false', 'false', 'false', 'false', '100000', NULL, 'false', 'false', 'false', 'false', NULL, NULL, NULL, 'false', 'false', 'consumer', 'false', NULL, NULL, 'false', '10', '4.5', '吴总', '统一社会信用代码', NULL, 'false', '若依-admin', '2026-01-30 16:38:24', '若依-admin', '2026-01-30 16:39:10'),
(3, '20260202140048990', 2, '892000', '1', 'TEST001', '个人', '信用', NULL, NULL, NULL, NULL, '500000', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'true', 'false', NULL, NULL, NULL, NULL, '张三', '身份证', '110101199001011234', NULL, '若依-admin', '2026-02-02 14:00:49', '若依-admin', '2026-02-02 14:00:50'),
(4, '20260202140101592', 3, '892000', '1', 'TEST002', '个人', '质押', NULL, NULL, NULL, NULL, '100000', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '若依-admin', '2026-02-02 14:01:02', '若依-admin', '2026-02-02 14:01:02'),
(5, '20260202140102337', 4, '892000', '1', 'TEST003', '个人', '抵押', NULL, NULL, NULL, NULL, '800000', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'true', 'true', '一类', 'false', NULL, NULL, '孙七', '身份证', '110101199001011239', NULL, '若依-admin', '2026-02-02 14:01:02', '若依-admin', '2026-02-02 14:01:03'),
(6, '20260202140119035', 2, '892000', '1', 'CORP001', '企业', '抵押', NULL, NULL, NULL, NULL, '1000000', '36', NULL, NULL, NULL, 'false', 'true', 'true', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '测试科技有限公司', '统一社会信用代码', '91110000100000000X', NULL, '若依-admin', '2026-02-02 14:01:19', '若依-admin', '2026-02-02 14:01:19'),
(7, '20260202140128799', 3, '892000', '1', 'CORP007', '企业', '信用', NULL, NULL, NULL, NULL, '3000000', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '若依-admin', '2026-02-02 14:01:29', '若依-admin', '2026-02-02 14:01:29'),
(8, '20260202140129480', 4, '892000', '1', 'CORP005', '企业', '保证', NULL, NULL, NULL, NULL, '2000000', '60', NULL, NULL, NULL, 'true', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '农业科技有限公司', '统一社会信用代码', '91110000100000005X', NULL, '若依-admin', '2026-02-02 14:01:29', '若依-admin', '2026-02-02 14:01:30'),
(9, '20260202140138984', 5, '892000', '1', 'OLD001', '个人', '信用', NULL, NULL, NULL, NULL, '500000', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'true', 'false', NULL, NULL, '4.5', NULL, '测试用户1', '身份证', NULL, NULL, '若依-admin', '2026-02-02 14:01:39', '若依-admin', '2026-02-02 14:01:39'),
(10, '20260202140145591', 5, '892000', '1', 'OLD002', '企业', '抵押', NULL, NULL, NULL, NULL, '1000000', '36', NULL, NULL, NULL, 'false', 'true', 'true', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '4.0', NULL, '测试企业1', '统一社会信用代码', NULL, NULL, '若依-admin', '2026-02-02 14:01:46', '若依-admin', '2026-02-02 14:01:46'),
(11, '20260202144250835', 6, '892000', '1', '1234567', '个人', '信用', NULL, NULL, NULL, NULL, '100000', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'true', 'true', '一线', 'true', NULL, NULL, '个人测试', '身份证', '330103199912311231', NULL, '若依-admin', '2026-02-02 14:42:51', '若依-admin', '2026-02-02 14:42:51'),
(12, '20260202151445788', 6, '892000', '1', 'test1234', '企业', '信用', NULL, NULL, NULL, NULL, '200000', '23', NULL, NULL, NULL, 'true', 'true', 'true', 'true', NULL, NULL, NULL, NULL, NULL, '一线', 'true', NULL, NULL, 'test1234', '统一社会信用代码', '91110000100000000X', NULL, '若依-admin', '2026-02-02 15:14:46', '若依-admin', '2026-02-02 15:14:46');
DELETE FROM `model_corp_output_fields`;
INSERT INTO `model_corp_output_fields` (`id`, `cust_isn`, `cust_type`, `guar_type`, `cust_name`, `id_type`, `id_num`, `base_loan_rate`, `is_first_loan`, `faith_day`, `bp_first_loan`, `bp_age_loan`, `total_bp_loyalty`, `balance_avg`, `loan_avg`, `derivation_rate`, `total_bp_contribution`, `mid_ent_connect`, `mid_ent_effect`, `mid_ent_inter`, `mid_ent_accept`, `mid_ent_discount`, `mid_ent_ele_ddc`, `mid_ent_water_ddc`, `mid_ent_tax`, `bp_mid`, `payroll`, `inv_loan_amount`, `bp_payroll`, `is_clean_ent`, `has_settle_acct`, `is_agri_guar`, `is_green_loan`, `is_tech_ent`, `bp_ent_type`, `totoal_bp_relevance`, `loan_term`, `bp_loan_term`, `apply_amt`, `bp_loan_amount`, `coll_type`, `coll_third_party`, `bp_collateral`, `grey_cust`, `prin_overdue`, `interest_overdue`, `card_overdue`, `bp_grey_overdue`, `totoal_bp_risk`, `total_bp`, `calculate_rate`, `create_time`) VALUES
(1, 'CUST20260121001', '企业客户', '抵押担保', '北京智联科技有限公司', '营业执照', '91110108MA00XXXXXX', '3.45', 'N', '730', '0', '5.2', '8.5', '5000000.00', '3000000.00', '1.8', '12.3', '100000.00', '50000.00', '80000.00', '200000.00', '150000.00', '30000.00', '10000.00', '40000.00', '6.8', '200', '2500000.00', '4.1', 'Y', 'Y', 'N', 'Y', 'Y', '7.5', '9.2', '36', '3.3', '5000000.00', '5.8', '房产抵押', 'N', '4.5', 'N', 'N', 'N', 'N', '0', '1.2', '48.2', '3.932', '2026-01-30 16:38:24'),
(2, 'CUST20260121001', '企业客户', '抵押担保', '北京智联科技有限公司', '营业执照', '91110108MA00XXXXXX', '3.45', 'N', '730', '0', '5.2', '8.5', '5000000.00', '3000000.00', '1.8', '12.3', '100000.00', '50000.00', '80000.00', '200000.00', '150000.00', '30000.00', '10000.00', '40000.00', '6.8', '200', '2500000.00', '4.1', 'Y', 'Y', 'N', 'Y', 'Y', '7.5', '9.2', '36', '3.3', '5000000.00', '5.8', '房产抵押', 'N', '4.5', 'N', 'N', 'N', 'N', '0', '1.2', '48.2', '3.932', '2026-02-02 14:01:19'),
(3, 'CUST20260121001', '企业客户', '抵押担保', '北京智联科技有限公司', '营业执照', '91110108MA00XXXXXX', '3.45', 'N', '730', '0', '5.2', '8.5', '5000000.00', '3000000.00', '1.8', '12.3', '100000.00', '50000.00', '80000.00', '200000.00', '150000.00', '30000.00', '10000.00', '40000.00', '6.8', '200', '2500000.00', '4.1', 'Y', 'Y', 'N', 'Y', 'Y', '7.5', '9.2', '36', '3.3', '5000000.00', '5.8', '房产抵押', 'N', '4.5', 'N', 'N', 'N', 'N', '0', '1.2', '48.2', '3.932', '2026-02-02 14:01:29'),
(4, 'CUST20260121001', '企业客户', '抵押担保', '北京智联科技有限公司', '营业执照', '91110108MA00XXXXXX', '3.45', 'N', '730', '0', '5.2', '8.5', '5000000.00', '3000000.00', '1.8', '12.3', '100000.00', '50000.00', '80000.00', '200000.00', '150000.00', '30000.00', '10000.00', '40000.00', '6.8', '200', '2500000.00', '4.1', 'Y', 'Y', 'N', 'Y', 'Y', '7.5', '9.2', '36', '3.3', '5000000.00', '5.8', '房产抵押', 'N', '4.5', 'N', 'N', 'N', 'N', '0', '1.2', '48.2', '3.932', '2026-02-02 14:01:30'),
(5, 'CUST20260121001', '企业客户', '抵押担保', '北京智联科技有限公司', '营业执照', '91110108MA00XXXXXX', '3.45', 'N', '730', '0', '5.2', '8.5', '5000000.00', '3000000.00', '1.8', '12.3', '100000.00', '50000.00', '80000.00', '200000.00', '150000.00', '30000.00', '10000.00', '40000.00', '6.8', '200', '2500000.00', '4.1', 'Y', 'Y', 'N', 'Y', 'Y', '7.5', '9.2', '36', '3.3', '5000000.00', '5.8', '房产抵押', 'N', '4.5', 'N', 'N', 'N', 'N', '0', '1.2', '48.2', '3.932', '2026-02-02 14:01:46'),
(6, 'CUST20260121001', '企业客户', '抵押担保', '北京智联科技有限公司', '营业执照', '91110108MA00XXXXXX', '3.45', 'N', '730', '0', '5.2', '8.5', '5000000.00', '3000000.00', '1.8', '12.3', '100000.00', '50000.00', '80000.00', '200000.00', '150000.00', '30000.00', '10000.00', '40000.00', '6.8', '200', '2500000.00', '4.1', 'Y', 'Y', 'N', 'Y', 'Y', '7.5', '9.2', '36', '3.3', '5000000.00', '5.8', '房产抵押', 'N', '4.5', 'N', 'N', 'N', 'N', '0', '1.2', '48.2', '3.932', '2026-02-02 15:14:46');
DELETE FROM `model_retail_output_fields`;
INSERT INTO `model_retail_output_fields` (`id`, `cust_isn`, `cust_type`, `guar_type`, `cust_name`, `id_type`, `id_num`, `base_loan_rate`, `is_first_loan`, `faith_day`, `cust_age`, `bp_first_loan`, `bp_age_loan`, `bp_age`, `total_bp_loyalty`, `balance_avg`, `loan_avg`, `derivation_rate`, `total_bp_contribution`, `mid_per_card`, `mid_per_pass`, `mid_per_harvest`, `mid_per_effect`, `mid_per_quick_pay`, `mid_per_ele_ddc`, `mid_per_water_ddc`, `mid_per_huashu_ddc`, `mid_per_gas_ddc`, `mid_per_citizencard`, `mid_per_fin_man`, `mid_per_etc`, `bp_mid`, `totoal_bp_relevance`, `apply_amt`, `bp_loan_amount`, `loan_purpose`, `biz_proof`, `bp_loan_use`, `loan_loop`, `bp_loan_loop`, `coll_type`, `coll_third_party`, `bp_collateral`, `grey_cust`, `prin_overdue`, `interest_overdue`, `card_overdue`, `bp_grey_overdue`, `totoal_bp_risk`, `total_bp`, `calculate_rate`, `create_time`) VALUES
(1, 'CUST20260121001', '个人', '信用担保', '张三', '身份证', '330106199001011234', '4.35', '', '365', '36', '50', '30', '20', '95', '50000.00', '100000.00', '1.2', '88', '1000.50', '500.00', '800.20', '', '300.00', '150.00', '80.00', '120.00', '90.00', '200.00', '5000.00', '180.00', '45', '90', '200000.00', '60', '个人消费', '', '55', '支持', '40', '无抵质押', '', '0', '', '', '', '', '98', '95', '350', '6.15', '2026-01-30 16:06:41'),
(2, 'CUST20260121001', '个人', '信用担保', '张三', '身份证', '330106199001011234', '4.35', '', '365', '36', '50', '30', '20', '95', '50000.00', '100000.00', '1.2', '88', '1000.50', '500.00', '800.20', '', '300.00', '150.00', '80.00', '120.00', '90.00', '200.00', '5000.00', '180.00', '45', '90', '200000.00', '60', '个人消费', '', '55', '支持', '40', '无抵质押', '', '0', '', '', '', '', '98', '95', '350', '6.15', '2026-02-02 14:00:49'),
(3, 'CUST20260121001', '个人', '信用担保', '张三', '身份证', '330106199001011234', '4.35', '', '365', '36', '50', '30', '20', '95', '50000.00', '100000.00', '1.2', '88', '1000.50', '500.00', '800.20', '', '300.00', '150.00', '80.00', '120.00', '90.00', '200.00', '5000.00', '180.00', '45', '90', '200000.00', '60', '个人消费', '', '55', '支持', '40', '无抵质押', '', '0', '', '', '', '', '98', '95', '350', '6.15', '2026-02-02 14:01:02'),
(4, 'CUST20260121001', '个人', '信用担保', '张三', '身份证', '330106199001011234', '4.35', '', '365', '36', '50', '30', '20', '95', '50000.00', '100000.00', '1.2', '88', '1000.50', '500.00', '800.20', '', '300.00', '150.00', '80.00', '120.00', '90.00', '200.00', '5000.00', '180.00', '45', '90', '200000.00', '60', '个人消费', '', '55', '支持', '40', '无抵质押', '', '0', '', '', '', '', '98', '95', '350', '6.15', '2026-02-02 14:01:03'),
(5, 'CUST20260121001', '个人', '信用担保', '张三', '身份证', '330106199001011234', '4.35', '', '365', '36', '50', '30', '20', '95', '50000.00', '100000.00', '1.2', '88', '1000.50', '500.00', '800.20', '', '300.00', '150.00', '80.00', '120.00', '90.00', '200.00', '5000.00', '180.00', '45', '90', '200000.00', '60', '个人消费', '', '55', '支持', '40', '无抵质押', '', '0', '', '', '', '', '98', '95', '350', '6.15', '2026-02-02 14:01:39'),
(6, 'CUST20260121001', '个人', '信用担保', '张三', '身份证', '330106199001011234', '4.35', '', '365', '36', '50', '30', '20', '95', '50000.00', '100000.00', '1.2', '88', '1000.50', '500.00', '800.20', '', '300.00', '150.00', '80.00', '120.00', '90.00', '200.00', '5000.00', '180.00', '45', '90', '200000.00', '60', '个人消费', '', '55', '支持', '40', '无抵质押', '', '0', '', '', '', '', '98', '95', '350', '6.15', '2026-02-02 14:42:51');
DELETE FROM `sys_config`;
INSERT INTO `sys_config` (`config_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES
(1, '主框架页-默认皮肤样式名称', 'sys.index.skinName', 'skin-blue', 'Y', 'admin', '2026-01-30 07:57:17', '', NULL, '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow'),
(2, '用户管理-账号初始密码', 'sys.user.initPassword', '123456', 'Y', 'admin', '2026-01-30 07:57:18', '', NULL, '初始化密码 123456'),
(3, '主框架页-侧边栏主题', 'sys.index.sideTheme', 'theme-dark', 'Y', 'admin', '2026-01-30 07:57:18', '', NULL, '深色主题theme-dark浅色主题theme-light'),
(4, '账号自助-验证码开关', 'sys.account.captchaEnabled', 'true', 'Y', 'admin', '2026-01-30 07:57:18', '', NULL, '是否开启验证码功能true开启false关闭'),
(5, '账号自助-是否开启用户注册功能', 'sys.account.registerUser', 'false', 'Y', 'admin', '2026-01-30 07:57:19', '', NULL, '是否开启注册用户功能true开启false关闭'),
(6, '用户登录-黑名单列表', 'sys.login.blackIPList', '', 'Y', 'admin', '2026-01-30 07:57:19', '', NULL, '设置登录IP黑名单限制多个匹配项以;分隔,支持匹配(*通配、网段)'),
(7, '用户管理-初始密码修改策略', 'sys.account.initPasswordModify', '1', 'Y', 'admin', '2026-01-30 07:57:19', '', NULL, '0初始密码修改策略关闭没有任何提示1提醒用户如果未修改初始密码则在登录时就会提醒修改密码对话框'),
(8, '用户管理-账号密码更新周期', 'sys.account.passwordValidateDays', '0', 'Y', 'admin', '2026-01-30 07:57:20', '', NULL, '密码更新周期填写数字数据初始化值为0不限制若修改必须为大于0小于365的正整数如果超过这个周期登录系统时则在登录时就会提醒修改密码对话框');
DELETE FROM `sys_dept`;
INSERT INTO `sys_dept` (`dept_id`, `parent_id`, `ancestors`, `dept_name`, `order_num`, `leader`, `phone`, `email`, `status`, `del_flag`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES
(100, 0, '0', '若依科技', 0, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2026-01-30 07:55:45', '', NULL),
(101, 100, '0,100', '深圳总公司', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2026-01-30 07:55:45', '', NULL),
(102, 100, '0,100', '长沙分公司', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2026-01-30 07:55:46', '', NULL),
(103, 101, '0,100,101', '研发部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2026-01-30 07:55:46', '', NULL),
(104, 101, '0,100,101', '市场部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2026-01-30 07:55:46', '', NULL),
(105, 101, '0,100,101', '测试部门', 3, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2026-01-30 07:55:47', '', NULL),
(106, 101, '0,100,101', '财务部门', 4, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2026-01-30 07:55:47', '', NULL),
(107, 101, '0,100,101', '运维部门', 5, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2026-01-30 07:55:47', '', NULL),
(108, 102, '0,100,102', '市场部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2026-01-30 07:55:48', '', NULL),
(109, 102, '0,100,102', '财务部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2026-01-30 07:55:48', '', NULL);
DELETE FROM `sys_dict_data`;
INSERT INTO `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES
(1, 1, '', '0', 'sys_user_sex', '', '', 'Y', '0', 'admin', '2026-01-30 07:57:06', '', NULL, '性别男'),
(2, 2, '', '1', 'sys_user_sex', '', '', 'N', '0', 'admin', '2026-01-30 07:57:07', '', NULL, '性别女'),
(3, 3, '未知', '2', 'sys_user_sex', '', '', 'N', '0', 'admin', '2026-01-30 07:57:07', '', NULL, '性别未知'),
(4, 1, '显示', '0', 'sys_show_hide', '', 'primary', 'Y', '0', 'admin', '2026-01-30 07:57:07', '', NULL, '显示菜单'),
(5, 2, '隐藏', '1', 'sys_show_hide', '', 'danger', 'N', '0', 'admin', '2026-01-30 07:57:08', '', NULL, '隐藏菜单'),
(6, 1, '正常', '0', 'sys_normal_disable', '', 'primary', 'Y', '0', 'admin', '2026-01-30 07:57:08', '', NULL, '正常状态'),
(7, 2, '停用', '1', 'sys_normal_disable', '', 'danger', 'N', '0', 'admin', '2026-01-30 07:57:08', '', NULL, '停用状态'),
(8, 1, '正常', '0', 'sys_job_status', '', 'primary', 'Y', '0', 'admin', '2026-01-30 07:57:09', '', NULL, '正常状态'),
(9, 2, '暂停', '1', 'sys_job_status', '', 'danger', 'N', '0', 'admin', '2026-01-30 07:57:09', '', NULL, '停用状态'),
(10, 1, '默认', 'DEFAULT', 'sys_job_group', '', '', 'Y', '0', 'admin', '2026-01-30 07:57:10', '', NULL, '默认分组'),
(11, 2, '系统', 'SYSTEM', 'sys_job_group', '', '', 'N', '0', 'admin', '2026-01-30 07:57:10', '', NULL, '系统分组'),
(12, 1, '', 'Y', 'sys_yes_no', '', 'primary', 'Y', '0', 'admin', '2026-01-30 07:57:10', '', NULL, '系统默认是'),
(13, 2, '', 'N', 'sys_yes_no', '', 'danger', 'N', '0', 'admin', '2026-01-30 07:57:11', '', NULL, '系统默认否'),
(14, 1, '通知', '1', 'sys_notice_type', '', 'warning', 'Y', '0', 'admin', '2026-01-30 07:57:11', '', NULL, '通知'),
(15, 2, '公告', '2', 'sys_notice_type', '', 'success', 'N', '0', 'admin', '2026-01-30 07:57:11', '', NULL, '公告'),
(16, 1, '正常', '0', 'sys_notice_status', '', 'primary', 'Y', '0', 'admin', '2026-01-30 07:57:12', '', NULL, '正常状态'),
(17, 2, '关闭', '1', 'sys_notice_status', '', 'danger', 'N', '0', 'admin', '2026-01-30 07:57:12', '', NULL, '关闭状态'),
(18, 99, '其他', '0', 'sys_oper_type', '', 'info', 'N', '0', 'admin', '2026-01-30 07:57:12', '', NULL, '其他操作'),
(19, 1, '新增', '1', 'sys_oper_type', '', 'info', 'N', '0', 'admin', '2026-01-30 07:57:13', '', NULL, '新增操作'),
(20, 2, '修改', '2', 'sys_oper_type', '', 'info', 'N', '0', 'admin', '2026-01-30 07:57:13', '', NULL, '修改操作'),
(21, 3, '删除', '3', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2026-01-30 07:57:13', '', NULL, '删除操作'),
(22, 4, '授权', '4', 'sys_oper_type', '', 'primary', 'N', '0', 'admin', '2026-01-30 07:57:14', '', NULL, '授权操作'),
(23, 5, '导出', '5', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2026-01-30 07:57:14', '', NULL, '导出操作'),
(24, 6, '导入', '6', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2026-01-30 07:57:14', '', NULL, '导入操作'),
(25, 7, '强退', '7', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2026-01-30 07:57:15', '', NULL, '强退操作'),
(26, 8, '生成代码', '8', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2026-01-30 07:57:15', '', NULL, '生成操作'),
(27, 9, '清空数据', '9', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2026-01-30 07:57:16', '', NULL, '清空操作'),
(28, 1, '成功', '0', 'sys_common_status', '', 'primary', 'N', '0', 'admin', '2026-01-30 07:57:16', '', NULL, '正常状态'),
(29, 2, '失败', '1', 'sys_common_status', '', 'danger', 'N', '0', 'admin', '2026-01-30 07:57:16', '', NULL, '停用状态');
DELETE FROM `sys_dict_type`;
INSERT INTO `sys_dict_type` (`dict_id`, `dict_name`, `dict_type`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES
(1, '用户性别', 'sys_user_sex', '0', 'admin', '2026-01-30 07:57:02', '', NULL, '用户性别列表'),
(2, '菜单状态', 'sys_show_hide', '0', 'admin', '2026-01-30 07:57:02', '', NULL, '菜单状态列表'),
(3, '系统开关', 'sys_normal_disable', '0', 'admin', '2026-01-30 07:57:03', '', NULL, '系统开关列表'),
(4, '任务状态', 'sys_job_status', '0', 'admin', '2026-01-30 07:57:03', '', NULL, '任务状态列表'),
(5, '任务分组', 'sys_job_group', '0', 'admin', '2026-01-30 07:57:03', '', NULL, '任务分组列表'),
(6, '系统是否', 'sys_yes_no', '0', 'admin', '2026-01-30 07:57:04', '', NULL, '系统是否列表'),
(7, '通知类型', 'sys_notice_type', '0', 'admin', '2026-01-30 07:57:04', '', NULL, '通知类型列表'),
(8, '通知状态', 'sys_notice_status', '0', 'admin', '2026-01-30 07:57:04', '', NULL, '通知状态列表'),
(9, '操作类型', 'sys_oper_type', '0', 'admin', '2026-01-30 07:57:05', '', NULL, '操作类型列表'),
(10, '系统状态', 'sys_common_status', '0', 'admin', '2026-01-30 07:57:05', '', NULL, '登录状态列表');
DELETE FROM `sys_job`;
INSERT INTO `sys_job` (`job_id`, `job_name`, `job_group`, `invoke_target`, `cron_expression`, `misfire_policy`, `concurrent`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES
(1, '系统默认(无参)', 'DEFAULT', 'ryTask.ryNoParams', '0/10 * * * * ?', '3', '1', '1', 'admin', '2026-01-30 07:57:21', '', NULL, ''),
(2, '系统默认(有参)', 'DEFAULT', 'ryTask.ryParams(\'ry\')', '0/15 * * * * ?', '3', '1', '1', 'admin', '2026-01-30 07:57:22', '', NULL, ''),
(3, '系统默认(多参)', 'DEFAULT', 'ryTask.ryMultipleParams(\'ry\', true, 2000L, 316.50D, 100)', '0/20 * * * * ?', '3', '1', '1', 'admin', '2026-01-30 07:57:22', '', NULL, '');
DELETE FROM `sys_menu`;
INSERT INTO `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `route_name`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES
(1, '系统管理', 0, 1, 'system', NULL, '', '', 1, 0, 'M', '0', '0', '', 'system', 'admin', '2026-01-30 07:55:54', '', NULL, '系统管理目录'),
(2, '系统监控', 0, 2, 'monitor', NULL, '', '', 1, 0, 'M', '0', '0', '', 'monitor', 'admin', '2026-01-30 07:55:55', '', NULL, '系统监控目录'),
(3, '系统工具', 0, 3, 'tool', NULL, '', '', 1, 0, 'M', '0', '0', '', 'tool', 'admin', '2026-01-30 07:55:55', '', NULL, '系统工具目录'),
(4, '若依官网', 0, 4, 'http://ruoyi.vip', NULL, '', '', 0, 0, 'M', '0', '0', '', 'guide', 'admin', '2026-01-30 07:55:55', '', NULL, '若依官网地址'),
(100, '用户管理', 1, 1, 'user', 'system/user/index', '', '', 1, 0, 'C', '0', '0', 'system:user:list', 'user', 'admin', '2026-01-30 07:55:56', '', NULL, '用户管理菜单'),
(101, '角色管理', 1, 2, 'role', 'system/role/index', '', '', 1, 0, 'C', '0', '0', 'system:role:list', 'peoples', 'admin', '2026-01-30 07:55:56', '', NULL, '角色管理菜单'),
(102, '菜单管理', 1, 3, 'menu', 'system/menu/index', '', '', 1, 0, 'C', '0', '0', 'system:menu:list', 'tree-table', 'admin', '2026-01-30 07:55:56', '', NULL, '菜单管理菜单'),
(103, '部门管理', 1, 4, 'dept', 'system/dept/index', '', '', 1, 0, 'C', '0', '0', 'system:dept:list', 'tree', 'admin', '2026-01-30 07:55:57', '', NULL, '部门管理菜单'),
(104, '岗位管理', 1, 5, 'post', 'system/post/index', '', '', 1, 0, 'C', '0', '0', 'system:post:list', 'post', 'admin', '2026-01-30 07:55:57', '', NULL, '岗位管理菜单'),
(105, '字典管理', 1, 6, 'dict', 'system/dict/index', '', '', 1, 0, 'C', '0', '0', 'system:dict:list', 'dict', 'admin', '2026-01-30 07:55:57', '', NULL, '字典管理菜单'),
(106, '参数设置', 1, 7, 'config', 'system/config/index', '', '', 1, 0, 'C', '0', '0', 'system:config:list', 'edit', 'admin', '2026-01-30 07:55:58', '', NULL, '参数设置菜单'),
(107, '通知公告', 1, 8, 'notice', 'system/notice/index', '', '', 1, 0, 'C', '0', '0', 'system:notice:list', 'message', 'admin', '2026-01-30 07:55:58', '', NULL, '通知公告菜单'),
(108, '日志管理', 1, 9, 'log', '', '', '', 1, 0, 'M', '0', '0', '', 'log', 'admin', '2026-01-30 07:55:58', '', NULL, '日志管理菜单'),
(109, '在线用户', 2, 1, 'online', 'monitor/online/index', '', '', 1, 0, 'C', '0', '0', 'monitor:online:list', 'online', 'admin', '2026-01-30 07:55:59', '', NULL, '在线用户菜单'),
(110, '定时任务', 2, 2, 'job', 'monitor/job/index', '', '', 1, 0, 'C', '0', '0', 'monitor:job:list', 'job', 'admin', '2026-01-30 07:55:59', '', NULL, '定时任务菜单'),
(111, '数据监控', 2, 3, 'druid', 'monitor/druid/index', '', '', 1, 0, 'C', '0', '0', 'monitor:druid:list', 'druid', 'admin', '2026-01-30 07:55:59', '', NULL, '数据监控菜单'),
(112, '服务监控', 2, 4, 'server', 'monitor/server/index', '', '', 1, 0, 'C', '0', '0', 'monitor:server:list', 'server', 'admin', '2026-01-30 07:56:00', '', NULL, '服务监控菜单'),
(113, '缓存监控', 2, 5, 'cache', 'monitor/cache/index', '', '', 1, 0, 'C', '0', '0', 'monitor:cache:list', 'redis', 'admin', '2026-01-30 07:56:00', '', NULL, '缓存监控菜单'),
(114, '缓存列表', 2, 6, 'cacheList', 'monitor/cache/list', '', '', 1, 0, 'C', '0', '0', 'monitor:cache:list', 'redis-list', 'admin', '2026-01-30 07:56:01', '', NULL, '缓存列表菜单'),
(115, '表单构建', 3, 1, 'build', 'tool/build/index', '', '', 1, 0, 'C', '0', '0', 'tool:build:list', 'build', 'admin', '2026-01-30 07:56:01', '', NULL, '表单构建菜单'),
(116, '代码生成', 3, 2, 'gen', 'tool/gen/index', '', '', 1, 0, 'C', '0', '0', 'tool:gen:list', 'code', 'admin', '2026-01-30 07:56:01', '', NULL, '代码生成菜单'),
(117, '系统接口', 3, 3, 'swagger', 'tool/swagger/index', '', '', 1, 0, 'C', '0', '0', 'tool:swagger:list', 'swagger', 'admin', '2026-01-30 07:56:02', '', NULL, '系统接口菜单'),
(500, '操作日志', 108, 1, 'operlog', 'monitor/operlog/index', '', '', 1, 0, 'C', '0', '0', 'monitor:operlog:list', 'form', 'admin', '2026-01-30 07:56:02', '', NULL, '操作日志菜单'),
(501, '登录日志', 108, 2, 'logininfor', 'monitor/logininfor/index', '', '', 1, 0, 'C', '0', '0', 'monitor:logininfor:list', 'logininfor', 'admin', '2026-01-30 07:56:02', '', NULL, '登录日志菜单'),
(1000, '用户查询', 100, 1, '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:query', '#', 'admin', '2026-01-30 07:56:03', '', NULL, ''),
(1001, '用户新增', 100, 2, '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:add', '#', 'admin', '2026-01-30 07:56:03', '', NULL, ''),
(1002, '用户修改', 100, 3, '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:edit', '#', 'admin', '2026-01-30 07:56:03', '', NULL, ''),
(1003, '用户删除', 100, 4, '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:remove', '#', 'admin', '2026-01-30 07:56:04', '', NULL, ''),
(1004, '用户导出', 100, 5, '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:export', '#', 'admin', '2026-01-30 07:56:04', '', NULL, ''),
(1005, '用户导入', 100, 6, '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:import', '#', 'admin', '2026-01-30 07:56:05', '', NULL, ''),
(1006, '重置密码', 100, 7, '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:resetPwd', '#', 'admin', '2026-01-30 07:56:05', '', NULL, ''),
(1007, '角色查询', 101, 1, '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:query', '#', 'admin', '2026-01-30 07:56:05', '', NULL, ''),
(1008, '角色新增', 101, 2, '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:add', '#', 'admin', '2026-01-30 07:56:06', '', NULL, ''),
(1009, '角色修改', 101, 3, '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:edit', '#', 'admin', '2026-01-30 07:56:06', '', NULL, ''),
(1010, '角色删除', 101, 4, '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:remove', '#', 'admin', '2026-01-30 07:56:06', '', NULL, ''),
(1011, '角色导出', 101, 5, '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:export', '#', 'admin', '2026-01-30 07:56:07', '', NULL, ''),
(1012, '菜单查询', 102, 1, '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:query', '#', 'admin', '2026-01-30 07:56:07', '', NULL, ''),
(1013, '菜单新增', 102, 2, '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:add', '#', 'admin', '2026-01-30 07:56:07', '', NULL, ''),
(1014, '菜单修改', 102, 3, '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:edit', '#', 'admin', '2026-01-30 07:56:08', '', NULL, ''),
(1015, '菜单删除', 102, 4, '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:remove', '#', 'admin', '2026-01-30 07:56:08', '', NULL, ''),
(1016, '部门查询', 103, 1, '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:query', '#', 'admin', '2026-01-30 07:56:09', '', NULL, ''),
(1017, '部门新增', 103, 2, '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:add', '#', 'admin', '2026-01-30 07:56:09', '', NULL, ''),
(1018, '部门修改', 103, 3, '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:edit', '#', 'admin', '2026-01-30 07:56:09', '', NULL, ''),
(1019, '部门删除', 103, 4, '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:remove', '#', 'admin', '2026-01-30 07:56:10', '', NULL, ''),
(1020, '岗位查询', 104, 1, '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:query', '#', 'admin', '2026-01-30 07:56:10', '', NULL, ''),
(1021, '岗位新增', 104, 2, '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:add', '#', 'admin', '2026-01-30 07:56:10', '', NULL, ''),
(1022, '岗位修改', 104, 3, '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:edit', '#', 'admin', '2026-01-30 07:56:11', '', NULL, ''),
(1023, '岗位删除', 104, 4, '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:remove', '#', 'admin', '2026-01-30 07:56:11', '', NULL, ''),
(1024, '岗位导出', 104, 5, '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:export', '#', 'admin', '2026-01-30 07:56:12', '', NULL, ''),
(1025, '字典查询', 105, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:query', '#', 'admin', '2026-01-30 07:56:12', '', NULL, ''),
(1026, '字典新增', 105, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:add', '#', 'admin', '2026-01-30 07:56:12', '', NULL, ''),
(1027, '字典修改', 105, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:edit', '#', 'admin', '2026-01-30 07:56:13', '', NULL, ''),
(1028, '字典删除', 105, 4, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:remove', '#', 'admin', '2026-01-30 07:56:13', '', NULL, ''),
(1029, '字典导出', 105, 5, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:export', '#', 'admin', '2026-01-30 07:56:13', '', NULL, ''),
(1030, '参数查询', 106, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:query', '#', 'admin', '2026-01-30 07:56:14', '', NULL, ''),
(1031, '参数新增', 106, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:add', '#', 'admin', '2026-01-30 07:56:14', '', NULL, ''),
(1032, '参数修改', 106, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:edit', '#', 'admin', '2026-01-30 07:56:15', '', NULL, ''),
(1033, '参数删除', 106, 4, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:remove', '#', 'admin', '2026-01-30 07:56:15', '', NULL, ''),
(1034, '参数导出', 106, 5, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:export', '#', 'admin', '2026-01-30 07:56:15', '', NULL, ''),
(1035, '公告查询', 107, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:query', '#', 'admin', '2026-01-30 07:56:16', '', NULL, ''),
(1036, '公告新增', 107, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:add', '#', 'admin', '2026-01-30 07:56:16', '', NULL, ''),
(1037, '公告修改', 107, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:edit', '#', 'admin', '2026-01-30 07:56:16', '', NULL, ''),
(1038, '公告删除', 107, 4, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:remove', '#', 'admin', '2026-01-30 07:56:17', '', NULL, ''),
(1039, '操作查询', 500, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:query', '#', 'admin', '2026-01-30 07:56:17', '', NULL, ''),
(1040, '操作删除', 500, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:remove', '#', 'admin', '2026-01-30 07:56:18', '', NULL, ''),
(1041, '日志导出', 500, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:export', '#', 'admin', '2026-01-30 07:56:18', '', NULL, ''),
(1042, '登录查询', 501, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:query', '#', 'admin', '2026-01-30 07:56:18', '', NULL, ''),
(1043, '登录删除', 501, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:remove', '#', 'admin', '2026-01-30 07:56:19', '', NULL, ''),
(1044, '日志导出', 501, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:export', '#', 'admin', '2026-01-30 07:56:19', '', NULL, ''),
(1045, '账户解锁', 501, 4, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:unlock', '#', 'admin', '2026-01-30 07:56:19', '', NULL, ''),
(1046, '在线查询', 109, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:online:query', '#', 'admin', '2026-01-30 07:56:20', '', NULL, ''),
(1047, '批量强退', 109, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:online:batchLogout', '#', 'admin', '2026-01-30 07:56:20', '', NULL, ''),
(1048, '单条强退', 109, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:online:forceLogout', '#', 'admin', '2026-01-30 07:56:20', '', NULL, ''),
(1049, '任务查询', 110, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:query', '#', 'admin', '2026-01-30 07:56:21', '', NULL, ''),
(1050, '任务新增', 110, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:add', '#', 'admin', '2026-01-30 07:56:21', '', NULL, ''),
(1051, '任务修改', 110, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:edit', '#', 'admin', '2026-01-30 07:56:22', '', NULL, ''),
(1052, '任务删除', 110, 4, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:remove', '#', 'admin', '2026-01-30 07:56:22', '', NULL, ''),
(1053, '状态修改', 110, 5, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:changeStatus', '#', 'admin', '2026-01-30 07:56:22', '', NULL, ''),
(1054, '任务导出', 110, 6, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:export', '#', 'admin', '2026-01-30 07:56:23', '', NULL, ''),
(1055, '生成查询', 116, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:query', '#', 'admin', '2026-01-30 07:56:23', '', NULL, ''),
(1056, '生成修改', 116, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:edit', '#', 'admin', '2026-01-30 07:56:23', '', NULL, ''),
(1057, '生成删除', 116, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:remove', '#', 'admin', '2026-01-30 07:56:24', '', NULL, ''),
(1058, '导入代码', 116, 4, '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:import', '#', 'admin', '2026-01-30 07:56:24', '', NULL, ''),
(1059, '预览代码', 116, 5, '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:preview', '#', 'admin', '2026-01-30 07:56:24', '', NULL, ''),
(1060, '生成代码', 116, 6, '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:code', '#', 'admin', '2026-01-30 07:56:25', '', NULL, ''),
(2000, '利率定价管理', 0, 5, 'loanPricing', NULL, NULL, '', 1, 0, 'M', '1', '0', '', 'money', 'admin', '2026-01-30 07:59:15', 'admin', '2026-01-30 08:05:37', ''),
(2001, '流程列表', 2000, 1, 'workflow', 'loanPricing/workflow/index', NULL, '', 1, 0, 'C', '0', '0', 'loanPricing:workflow:list', 'list', 'admin', '2026-01-30 07:59:15', '', NULL, ''),
(2002, '流程查询', 2001, 1, '', '', NULL, '', 1, 0, 'F', '0', '0', 'loanPricing:workflow:query', '#', 'admin', '2026-01-30 07:59:16', '', NULL, '');
DELETE FROM `sys_notice`;
INSERT INTO `sys_notice` (`notice_id`, `notice_title`, `notice_type`, `notice_content`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES
(1, '温馨提醒2018-07-01 若依新版本发布啦', '2', 0xe696b0e78988e69cace58685e5aeb9, '0', 'admin', '2026-01-30 07:57:24', '', NULL, '管理员'),
(2, '维护通知2018-07-01 若依系统凌晨维护', '1', 0xe7bbb4e68aa4e58685e5aeb9, '0', 'admin', '2026-01-30 07:57:24', '', NULL, '管理员');
DELETE FROM `sys_post`;
INSERT INTO `sys_post` (`post_id`, `post_code`, `post_name`, `post_sort`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES
(1, 'ceo', '董事长', 1, '0', 'admin', '2026-01-30 07:55:51', '', NULL, ''),
(2, 'se', '项目经理', 2, '0', 'admin', '2026-01-30 07:55:51', '', NULL, ''),
(3, 'hr', '人力资源', 3, '0', 'admin', '2026-01-30 07:55:51', '', NULL, ''),
(4, 'user', '普通员工', 4, '0', 'admin', '2026-01-30 07:55:52', '', NULL, '');
DELETE FROM `sys_role`;
INSERT INTO `sys_role` (`role_id`, `role_name`, `role_key`, `role_sort`, `data_scope`, `menu_check_strictly`, `dept_check_strictly`, `status`, `del_flag`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES
(1, '超级管理员', 'admin', 1, '1', 1, 1, '0', '0', 'admin', '2026-01-30 07:55:53', '', NULL, '超级管理员'),
(2, '普通角色', 'common', 2, '2', 1, 1, '0', '0', 'admin', '2026-01-30 07:55:53', '', NULL, '普通角色'),
(100, '管理员', 'headAdmin', 0, '1', 1, 1, '0', '0', 'admin', '2026-01-30 08:43:12', '', NULL, NULL);
DELETE FROM `sys_role_dept`;
INSERT INTO `sys_role_dept` (`role_id`, `dept_id`) VALUES
(2, 100),
(2, 101),
(2, 105);
DELETE FROM `sys_role_menu`;
INSERT INTO `sys_role_menu` (`role_id`, `menu_id`) VALUES
(1, 2000),
(1, 2001),
(1, 2002),
(2, 1),
(2, 2),
(2, 3),
(2, 4),
(2, 100),
(2, 101),
(2, 102),
(2, 103),
(2, 104),
(2, 105),
(2, 106),
(2, 107),
(2, 108),
(2, 109),
(2, 110),
(2, 111),
(2, 112),
(2, 113),
(2, 114),
(2, 115),
(2, 116),
(2, 117),
(2, 500),
(2, 501),
(2, 1000),
(2, 1001),
(2, 1002),
(2, 1003),
(2, 1004),
(2, 1005),
(2, 1006),
(2, 1007),
(2, 1008),
(2, 1009),
(2, 1010),
(2, 1011),
(2, 1012),
(2, 1013),
(2, 1014),
(2, 1015),
(2, 1016),
(2, 1017),
(2, 1018),
(2, 1019),
(2, 1020),
(2, 1021),
(2, 1022),
(2, 1023),
(2, 1024),
(2, 1025),
(2, 1026),
(2, 1027),
(2, 1028),
(2, 1029),
(2, 1030),
(2, 1031),
(2, 1032),
(2, 1033),
(2, 1034),
(2, 1035),
(2, 1036),
(2, 1037),
(2, 1038),
(2, 1039),
(2, 1040),
(2, 1041),
(2, 1042),
(2, 1043),
(2, 1044),
(2, 1045),
(2, 1046),
(2, 1047),
(2, 1048),
(2, 1049),
(2, 1050),
(2, 1051),
(2, 1052),
(2, 1053),
(2, 1054),
(2, 1055),
(2, 1056),
(2, 1057),
(2, 1058),
(2, 1059),
(2, 1060),
(100, 1),
(100, 100),
(100, 101),
(100, 102),
(100, 103),
(100, 1000),
(100, 1001),
(100, 1002),
(100, 1003),
(100, 1004),
(100, 1005),
(100, 1006),
(100, 1007),
(100, 1008),
(100, 1009),
(100, 1010),
(100, 1011),
(100, 1012),
(100, 1013),
(100, 1014),
(100, 1015),
(100, 1016),
(100, 1017),
(100, 1018),
(100, 1019),
(100, 2000),
(100, 2001),
(100, 2002);
DELETE FROM `sys_user`;
INSERT INTO `sys_user` (`user_id`, `dept_id`, `user_name`, `nick_name`, `user_type`, `email`, `phonenumber`, `sex`, `avatar`, `password`, `status`, `del_flag`, `login_ip`, `login_date`, `pwd_update_date`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES
(1, 103, 'admin', '若依', '00', 'ry@163.com', '15888888888', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', '2026-03-28 09:16:04', '2026-01-30 07:55:49', 'admin', '2026-01-30 07:55:49', '', NULL, '管理员'),
(2, 105, 'ry', '若依', '00', 'ry@qq.com', '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', '2026-01-30 07:55:50', '2026-01-30 07:55:50', 'admin', '2026-01-30 07:55:50', '', NULL, '测试员'),
(100, 100, '8929999', '测试管理员', '00', '', '', '0', '', '$2a$10$i1YqCkEgZK4YhJC09y3qAOovK13Sc5oOENYtFGZRU6R/z8jJB/C/W', '0', '0', '127.0.0.1', '2026-01-30 16:44:03', NULL, 'admin', '2026-01-30 08:43:45', '', NULL, NULL);
DELETE FROM `sys_user_post`;
INSERT INTO `sys_user_post` (`user_id`, `post_id`) VALUES
(1, 1),
(2, 2);
DELETE FROM `sys_user_role`;
INSERT INTO `sys_user_role` (`user_id`, `role_id`) VALUES
(1, 1),
(2, 2),
(100, 100);
SET FOREIGN_KEY_CHECKS=1;

View File

@@ -0,0 +1,893 @@
-- 说明:
-- 1. 本文件由源库 116.62.17.81:3306/loan-pricing 导出
-- 2. 用途是初始化目标库 116.62.17.81:3307 的全部表结构
-- 3. 导入前请先创建目标数据库账号并确认拥有建库建表权限
-- MySQL dump 10.13 Distrib 9.6.0, for macos15 (arm64)
--
-- Host: 116.62.17.81 Database: loan-pricing
-- ------------------------------------------------------
-- Server version 5.7.44
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!50503 SET NAMES utf8mb4 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
--
-- Current Database: `loan-pricing`
--
CREATE DATABASE /*!32312 IF NOT EXISTS*/ `loan-pricing` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci */;
USE `loan-pricing`;
--
-- Table structure for table `QRTZ_BLOB_TRIGGERS`
--
DROP TABLE IF EXISTS `QRTZ_BLOB_TRIGGERS`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `QRTZ_BLOB_TRIGGERS` (
`sched_name` varchar(120) NOT NULL COMMENT '调度名称',
`trigger_name` varchar(200) NOT NULL COMMENT 'qrtz_triggers表trigger_name的外键',
`trigger_group` varchar(200) NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键',
`blob_data` blob COMMENT '存放持久化Trigger对象',
PRIMARY KEY (`sched_name`,`trigger_name`,`trigger_group`),
CONSTRAINT `QRTZ_BLOB_TRIGGERS_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `QRTZ_TRIGGERS` (`sched_name`, `trigger_name`, `trigger_group`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='Blob类型的触发器表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `QRTZ_CALENDARS`
--
DROP TABLE IF EXISTS `QRTZ_CALENDARS`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `QRTZ_CALENDARS` (
`sched_name` varchar(120) NOT NULL COMMENT '调度名称',
`calendar_name` varchar(200) NOT NULL COMMENT '日历名称',
`calendar` blob NOT NULL COMMENT '存放持久化calendar对象',
PRIMARY KEY (`sched_name`,`calendar_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='日历信息表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `QRTZ_CRON_TRIGGERS`
--
DROP TABLE IF EXISTS `QRTZ_CRON_TRIGGERS`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `QRTZ_CRON_TRIGGERS` (
`sched_name` varchar(120) NOT NULL COMMENT '调度名称',
`trigger_name` varchar(200) NOT NULL COMMENT 'qrtz_triggers表trigger_name的外键',
`trigger_group` varchar(200) NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键',
`cron_expression` varchar(200) NOT NULL COMMENT 'cron表达式',
`time_zone_id` varchar(80) DEFAULT NULL COMMENT '时区',
PRIMARY KEY (`sched_name`,`trigger_name`,`trigger_group`),
CONSTRAINT `QRTZ_CRON_TRIGGERS_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `QRTZ_TRIGGERS` (`sched_name`, `trigger_name`, `trigger_group`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='Cron类型的触发器表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `QRTZ_FIRED_TRIGGERS`
--
DROP TABLE IF EXISTS `QRTZ_FIRED_TRIGGERS`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `QRTZ_FIRED_TRIGGERS` (
`sched_name` varchar(120) NOT NULL COMMENT '调度名称',
`entry_id` varchar(95) NOT NULL COMMENT '调度器实例id',
`trigger_name` varchar(200) NOT NULL COMMENT 'qrtz_triggers表trigger_name的外键',
`trigger_group` varchar(200) NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键',
`instance_name` varchar(200) NOT NULL COMMENT '调度器实例名',
`fired_time` bigint(13) NOT NULL COMMENT '触发的时间',
`sched_time` bigint(13) NOT NULL COMMENT '定时器制定的时间',
`priority` int(11) NOT NULL COMMENT '优先级',
`state` varchar(16) NOT NULL COMMENT '状态',
`job_name` varchar(200) DEFAULT NULL COMMENT '任务名称',
`job_group` varchar(200) DEFAULT NULL COMMENT '任务组名',
`is_nonconcurrent` varchar(1) DEFAULT NULL COMMENT '是否并发',
`requests_recovery` varchar(1) DEFAULT NULL COMMENT '是否接受恢复执行',
PRIMARY KEY (`sched_name`,`entry_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='已触发的触发器表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `QRTZ_JOB_DETAILS`
--
DROP TABLE IF EXISTS `QRTZ_JOB_DETAILS`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `QRTZ_JOB_DETAILS` (
`sched_name` varchar(120) NOT NULL COMMENT '调度名称',
`job_name` varchar(200) NOT NULL COMMENT '任务名称',
`job_group` varchar(200) NOT NULL COMMENT '任务组名',
`description` varchar(250) DEFAULT NULL COMMENT '相关介绍',
`job_class_name` varchar(250) NOT NULL COMMENT '执行任务类名称',
`is_durable` varchar(1) NOT NULL COMMENT '是否持久化',
`is_nonconcurrent` varchar(1) NOT NULL COMMENT '是否并发',
`is_update_data` varchar(1) NOT NULL COMMENT '是否更新数据',
`requests_recovery` varchar(1) NOT NULL COMMENT '是否接受恢复执行',
`job_data` blob COMMENT '存放持久化job对象',
PRIMARY KEY (`sched_name`,`job_name`,`job_group`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='任务详细信息表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `QRTZ_LOCKS`
--
DROP TABLE IF EXISTS `QRTZ_LOCKS`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `QRTZ_LOCKS` (
`sched_name` varchar(120) NOT NULL COMMENT '调度名称',
`lock_name` varchar(40) NOT NULL COMMENT '悲观锁名称',
PRIMARY KEY (`sched_name`,`lock_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='存储的悲观锁信息表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `QRTZ_PAUSED_TRIGGER_GRPS`
--
DROP TABLE IF EXISTS `QRTZ_PAUSED_TRIGGER_GRPS`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `QRTZ_PAUSED_TRIGGER_GRPS` (
`sched_name` varchar(120) NOT NULL COMMENT '调度名称',
`trigger_group` varchar(200) NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键',
PRIMARY KEY (`sched_name`,`trigger_group`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='暂停的触发器表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `QRTZ_SCHEDULER_STATE`
--
DROP TABLE IF EXISTS `QRTZ_SCHEDULER_STATE`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `QRTZ_SCHEDULER_STATE` (
`sched_name` varchar(120) NOT NULL COMMENT '调度名称',
`instance_name` varchar(200) NOT NULL COMMENT '实例名称',
`last_checkin_time` bigint(13) NOT NULL COMMENT '上次检查时间',
`checkin_interval` bigint(13) NOT NULL COMMENT '检查间隔时间',
PRIMARY KEY (`sched_name`,`instance_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='调度器状态表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `QRTZ_SIMPLE_TRIGGERS`
--
DROP TABLE IF EXISTS `QRTZ_SIMPLE_TRIGGERS`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `QRTZ_SIMPLE_TRIGGERS` (
`sched_name` varchar(120) NOT NULL COMMENT '调度名称',
`trigger_name` varchar(200) NOT NULL COMMENT 'qrtz_triggers表trigger_name的外键',
`trigger_group` varchar(200) NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键',
`repeat_count` bigint(7) NOT NULL COMMENT '重复的次数统计',
`repeat_interval` bigint(12) NOT NULL COMMENT '重复的间隔时间',
`times_triggered` bigint(10) NOT NULL COMMENT '已经触发的次数',
PRIMARY KEY (`sched_name`,`trigger_name`,`trigger_group`),
CONSTRAINT `QRTZ_SIMPLE_TRIGGERS_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `QRTZ_TRIGGERS` (`sched_name`, `trigger_name`, `trigger_group`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='简单触发器的信息表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `QRTZ_SIMPROP_TRIGGERS`
--
DROP TABLE IF EXISTS `QRTZ_SIMPROP_TRIGGERS`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `QRTZ_SIMPROP_TRIGGERS` (
`sched_name` varchar(120) NOT NULL COMMENT '调度名称',
`trigger_name` varchar(200) NOT NULL COMMENT 'qrtz_triggers表trigger_name的外键',
`trigger_group` varchar(200) NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键',
`str_prop_1` varchar(512) DEFAULT NULL COMMENT 'String类型的trigger的第一个参数',
`str_prop_2` varchar(512) DEFAULT NULL COMMENT 'String类型的trigger的第二个参数',
`str_prop_3` varchar(512) DEFAULT NULL COMMENT 'String类型的trigger的第三个参数',
`int_prop_1` int(11) DEFAULT NULL COMMENT 'int类型的trigger的第一个参数',
`int_prop_2` int(11) DEFAULT NULL COMMENT 'int类型的trigger的第二个参数',
`long_prop_1` bigint(20) DEFAULT NULL COMMENT 'long类型的trigger的第一个参数',
`long_prop_2` bigint(20) DEFAULT NULL COMMENT 'long类型的trigger的第二个参数',
`dec_prop_1` decimal(13,4) DEFAULT NULL COMMENT 'decimal类型的trigger的第一个参数',
`dec_prop_2` decimal(13,4) DEFAULT NULL COMMENT 'decimal类型的trigger的第二个参数',
`bool_prop_1` varchar(1) DEFAULT NULL COMMENT 'Boolean类型的trigger的第一个参数',
`bool_prop_2` varchar(1) DEFAULT NULL COMMENT 'Boolean类型的trigger的第二个参数',
PRIMARY KEY (`sched_name`,`trigger_name`,`trigger_group`),
CONSTRAINT `QRTZ_SIMPROP_TRIGGERS_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `QRTZ_TRIGGERS` (`sched_name`, `trigger_name`, `trigger_group`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='同步机制的行锁表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `QRTZ_TRIGGERS`
--
DROP TABLE IF EXISTS `QRTZ_TRIGGERS`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `QRTZ_TRIGGERS` (
`sched_name` varchar(120) NOT NULL COMMENT '调度名称',
`trigger_name` varchar(200) NOT NULL COMMENT '触发器的名字',
`trigger_group` varchar(200) NOT NULL COMMENT '触发器所属组的名字',
`job_name` varchar(200) NOT NULL COMMENT 'qrtz_job_details表job_name的外键',
`job_group` varchar(200) NOT NULL COMMENT 'qrtz_job_details表job_group的外键',
`description` varchar(250) DEFAULT NULL COMMENT '相关介绍',
`next_fire_time` bigint(13) DEFAULT NULL COMMENT '上一次触发时间(毫秒)',
`prev_fire_time` bigint(13) DEFAULT NULL COMMENT '下一次触发时间(默认为-1表示不触发',
`priority` int(11) DEFAULT NULL COMMENT '优先级',
`trigger_state` varchar(16) NOT NULL COMMENT '触发器状态',
`trigger_type` varchar(8) NOT NULL COMMENT '触发器的类型',
`start_time` bigint(13) NOT NULL COMMENT '开始时间',
`end_time` bigint(13) DEFAULT NULL COMMENT '结束时间',
`calendar_name` varchar(200) DEFAULT NULL COMMENT '日程表名称',
`misfire_instr` smallint(2) DEFAULT NULL COMMENT '补偿执行的策略',
`job_data` blob COMMENT '存放持久化job对象',
PRIMARY KEY (`sched_name`,`trigger_name`,`trigger_group`),
KEY `sched_name` (`sched_name`,`job_name`,`job_group`),
CONSTRAINT `QRTZ_TRIGGERS_ibfk_1` FOREIGN KEY (`sched_name`, `job_name`, `job_group`) REFERENCES `QRTZ_JOB_DETAILS` (`sched_name`, `job_name`, `job_group`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='触发器详细信息表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `gen_table`
--
DROP TABLE IF EXISTS `gen_table`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `gen_table` (
`table_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
`table_name` varchar(200) DEFAULT '' COMMENT '表名称',
`table_comment` varchar(500) DEFAULT '' COMMENT '表描述',
`sub_table_name` varchar(64) DEFAULT NULL COMMENT '关联子表的表名',
`sub_table_fk_name` varchar(64) DEFAULT NULL COMMENT '子表关联的外键名',
`class_name` varchar(100) DEFAULT '' COMMENT '实体类名称',
`tpl_category` varchar(200) DEFAULT 'crud' COMMENT '使用的模板crud单表操作 tree树表操作',
`tpl_web_type` varchar(30) DEFAULT '' COMMENT '前端模板类型element-ui模版 element-plus模版',
`package_name` varchar(100) DEFAULT NULL COMMENT '生成包路径',
`module_name` varchar(30) DEFAULT NULL COMMENT '生成模块名',
`business_name` varchar(30) DEFAULT NULL COMMENT '生成业务名',
`function_name` varchar(50) DEFAULT NULL COMMENT '生成功能名',
`function_author` varchar(50) DEFAULT NULL COMMENT '生成功能作者',
`gen_type` char(1) DEFAULT '0' COMMENT '生成代码方式0zip压缩包 1自定义路径',
`gen_path` varchar(200) DEFAULT '/' COMMENT '生成路径(不填默认项目路径)',
`options` varchar(1000) DEFAULT NULL COMMENT '其它生成选项',
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`table_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='代码生成业务表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `gen_table_column`
--
DROP TABLE IF EXISTS `gen_table_column`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `gen_table_column` (
`column_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
`table_id` bigint(20) DEFAULT NULL COMMENT '归属表编号',
`column_name` varchar(200) DEFAULT NULL COMMENT '列名称',
`column_comment` varchar(500) DEFAULT NULL COMMENT '列描述',
`column_type` varchar(100) DEFAULT NULL COMMENT '列类型',
`java_type` varchar(500) DEFAULT NULL COMMENT 'JAVA类型',
`java_field` varchar(200) DEFAULT NULL COMMENT 'JAVA字段名',
`is_pk` char(1) DEFAULT NULL COMMENT '是否主键1是',
`is_increment` char(1) DEFAULT NULL COMMENT '是否自增1是',
`is_required` char(1) DEFAULT NULL COMMENT '是否必填1是',
`is_insert` char(1) DEFAULT NULL COMMENT '是否为插入字段1是',
`is_edit` char(1) DEFAULT NULL COMMENT '是否编辑字段1是',
`is_list` char(1) DEFAULT NULL COMMENT '是否列表字段1是',
`is_query` char(1) DEFAULT NULL COMMENT '是否查询字段1是',
`query_type` varchar(200) DEFAULT 'EQ' COMMENT '查询方式(等于、不等于、大于、小于、范围)',
`html_type` varchar(200) DEFAULT NULL COMMENT '显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)',
`dict_type` varchar(200) DEFAULT '' COMMENT '字典类型',
`sort` int(11) DEFAULT NULL COMMENT '排序',
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`column_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='代码生成业务表字段';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `loan_pricing_workflow`
--
DROP TABLE IF EXISTS `loan_pricing_workflow`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `loan_pricing_workflow` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`serial_num` varchar(50) NOT NULL COMMENT '业务方流水号',
`model_output_id` bigint(20) DEFAULT NULL COMMENT '模型输出ID',
`org_code` varchar(20) NOT NULL DEFAULT '' COMMENT '机构编码',
`run_type` varchar(10) NOT NULL DEFAULT '1' COMMENT '运行模式: 1-同步',
`cust_isn` varchar(50) NOT NULL COMMENT '客户内码',
`cust_type` varchar(20) NOT NULL COMMENT '客户类型: 个人/企业',
`guar_type` varchar(20) NOT NULL COMMENT '担保方式: 信用/保证/抵押/质押',
`mid_per_quick_pay` varchar(10) DEFAULT NULL COMMENT '中间业务_个人_快捷支付: true/false',
`mid_per_ele_ddc` varchar(10) DEFAULT NULL COMMENT '中间业务_个人_电费代扣: true/false',
`mid_ent_ele_ddc` varchar(10) DEFAULT NULL COMMENT '中间业务_企业_电费代扣: true/false',
`mid_ent_water_ddc` varchar(10) DEFAULT NULL COMMENT '中间业务_企业_水费代扣: true/false',
`apply_amt` varchar(50) NOT NULL COMMENT '申请金额(元)',
`loan_term` varchar(50) DEFAULT NULL COMMENT '贷款期限',
`is_clean_ent` varchar(10) DEFAULT NULL COMMENT '净身企业: true/false',
`has_settle_acct` varchar(10) DEFAULT NULL COMMENT '开立基本结算账户: true/false',
`is_manufacturing` varchar(10) DEFAULT NULL COMMENT '制造业企业: true/false',
`is_agri_guar` varchar(10) DEFAULT NULL COMMENT '省农担担保贷款: true/false',
`is_tech_ent` varchar(10) DEFAULT NULL COMMENT '科技型企业: true/false科技型企业最多下降5BP',
`is_green_loan` varchar(10) DEFAULT NULL COMMENT '绿色贷款: true/false绿色贷款最多下降5BP',
`is_trade_construction` varchar(10) DEFAULT NULL COMMENT '贸易和建筑业企业标识: true/false抵质押类上调20BP',
`is_tax_a` varchar(10) DEFAULT NULL COMMENT '是否纳税信用等级A级: true/false',
`is_agri_leading` varchar(10) DEFAULT NULL COMMENT '是否县级及以上农业龙头企业: true/false',
`loan_purpose` varchar(20) DEFAULT NULL COMMENT '贷款用途: consumer-消费/business-经营',
`biz_proof` varchar(10) DEFAULT NULL COMMENT '是否有经营佐证: true/false',
`loan_loop` varchar(10) DEFAULT NULL COMMENT '循环功能: true/false贷款合同是否开通循环功能',
`coll_type` varchar(20) DEFAULT NULL COMMENT '抵质押类型: 一线/一类/二类',
`coll_third_party` varchar(10) DEFAULT NULL COMMENT '抵质押物是否三方所有: true/false',
`loan_rate` varchar(20) DEFAULT NULL COMMENT '贷款利率',
`execute_rate` varchar(20) DEFAULT NULL COMMENT '执行利率(%)',
`cust_name` varchar(100) DEFAULT NULL COMMENT '客户名称',
`id_type` varchar(50) DEFAULT NULL COMMENT '证件类型',
`id_num` varchar(100) DEFAULT NULL COMMENT '证件号码',
`is_inclusive_finance` varchar(10) DEFAULT NULL COMMENT '是否普惠小微借款人: true/false',
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_serial_num` (`serial_num`),
KEY `idx_org_code` (`org_code`),
KEY `idx_create_by` (`create_by`),
KEY `idx_cust_name` (`cust_name`),
KEY `idx_update_time` (`update_time`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='利率定价流程表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `model_corp_output_fields`
--
DROP TABLE IF EXISTS `model_corp_output_fields`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `model_corp_output_fields` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键ID',
`cust_isn` varchar(100) DEFAULT NULL COMMENT '客户内码',
`cust_type` varchar(100) DEFAULT NULL COMMENT '客户类型',
`guar_type` varchar(100) DEFAULT NULL COMMENT '担保方式',
`cust_name` varchar(100) DEFAULT NULL COMMENT '客户名称',
`id_type` varchar(100) DEFAULT NULL COMMENT '证件类型',
`id_num` varchar(100) DEFAULT NULL COMMENT '证件号码',
`base_loan_rate` varchar(100) DEFAULT NULL COMMENT '基准利率',
`is_first_loan` varchar(100) DEFAULT NULL COMMENT '我行首贷客户',
`faith_day` varchar(100) DEFAULT NULL COMMENT '用信天数',
`bp_first_loan` varchar(100) DEFAULT NULL COMMENT 'BP_首贷',
`bp_age_loan` varchar(100) DEFAULT NULL COMMENT 'BP_贷龄',
`total_bp_loyalty` varchar(100) DEFAULT NULL COMMENT 'TOTAL_BP_忠诚度',
`balance_avg` varchar(100) DEFAULT NULL COMMENT '存款年日均',
`loan_avg` varchar(100) DEFAULT NULL COMMENT '贷款年日均',
`derivation_rate` varchar(100) DEFAULT NULL COMMENT '派生率',
`total_bp_contribution` varchar(100) DEFAULT NULL COMMENT 'TOTAL_BP_贡献度',
`mid_ent_connect` varchar(100) DEFAULT NULL COMMENT '中间业务_企业_企业互联',
`mid_ent_effect` varchar(100) DEFAULT NULL COMMENT '中间业务_企业_有效价值客户',
`mid_ent_inter` varchar(100) DEFAULT NULL COMMENT '中间业务_企业_国际业务',
`mid_ent_accept` varchar(100) DEFAULT NULL COMMENT '中间业务_企业_承兑',
`mid_ent_discount` varchar(100) DEFAULT NULL COMMENT '中间业务_企业_贴现',
`mid_ent_ele_ddc` varchar(100) DEFAULT NULL COMMENT '中间业务_企业_电费代扣',
`mid_ent_water_ddc` varchar(100) DEFAULT NULL COMMENT '中间业务_企业_水费代扣',
`mid_ent_tax` varchar(100) DEFAULT NULL COMMENT '中间业务_企业_税务代扣',
`bp_mid` varchar(100) DEFAULT NULL COMMENT 'BP_中间业务',
`payroll` varchar(100) DEFAULT NULL COMMENT '代发工资户数',
`inv_loan_amount` varchar(100) DEFAULT NULL COMMENT '存量贷款余额',
`bp_payroll` varchar(100) DEFAULT NULL COMMENT 'BP_代发工资',
`is_clean_ent` varchar(100) DEFAULT NULL COMMENT '净身企业',
`has_settle_acct` varchar(100) DEFAULT NULL COMMENT '开立基本结算账户',
`is_agri_guar` varchar(100) DEFAULT NULL COMMENT '省农担担保贷款',
`is_green_loan` varchar(100) DEFAULT NULL COMMENT '绿色贷款',
`is_tech_ent` varchar(100) DEFAULT NULL COMMENT '科技型企业',
`bp_ent_type` varchar(100) DEFAULT NULL COMMENT 'BP_企业客户类别',
`totoal_bp_relevance` varchar(100) DEFAULT NULL COMMENT 'TOTAL_BP_关联度',
`loan_term` varchar(100) DEFAULT NULL COMMENT '贷款期限',
`bp_loan_term` varchar(100) DEFAULT NULL COMMENT 'BP_贷款期限',
`apply_amt` varchar(100) DEFAULT NULL COMMENT '申请金额',
`bp_loan_amount` varchar(100) DEFAULT NULL COMMENT 'BP_贷款额度',
`coll_type` varchar(100) DEFAULT NULL COMMENT '抵质押类型',
`coll_third_party` varchar(100) DEFAULT NULL COMMENT '抵质押物是否三方所有',
`bp_collateral` varchar(100) DEFAULT NULL COMMENT 'BP_抵押物',
`grey_cust` varchar(100) DEFAULT NULL COMMENT '灰名单客户',
`prin_overdue` varchar(100) DEFAULT NULL COMMENT '本金逾期',
`interest_overdue` varchar(100) DEFAULT NULL COMMENT '利息逾期',
`card_overdue` varchar(100) DEFAULT NULL COMMENT '信用卡逾期',
`bp_grey_overdue` varchar(100) DEFAULT NULL COMMENT 'BP_灰名单与逾期',
`totoal_bp_risk` varchar(100) DEFAULT NULL COMMENT 'TOTAL_BP_风险度',
`total_bp` varchar(100) DEFAULT NULL COMMENT '浮动BP',
`calculate_rate` varchar(100) DEFAULT NULL COMMENT '测算利率',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='客户贷款利率测算表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `model_retail_output_fields`
--
DROP TABLE IF EXISTS `model_retail_output_fields`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `model_retail_output_fields` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`cust_isn` varchar(100) COLLATE utf8mb4_general_ci NOT NULL COMMENT '客户内码',
`cust_type` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '客户类型',
`guar_type` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '担保方式',
`cust_name` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '客户名称',
`id_type` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '证件类型',
`id_num` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '证件号码',
`base_loan_rate` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '基准利率',
`is_first_loan` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '我行首贷客户',
`faith_day` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '用信天数',
`cust_age` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '客户年龄',
`bp_first_loan` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'BP_首贷',
`bp_age_loan` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'BP_贷龄',
`bp_age` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'BP_年龄',
`total_bp_loyalty` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'TOTAL_BP_忠诚度',
`balance_avg` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '存款年日均',
`loan_avg` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '贷款年日均',
`derivation_rate` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '派生率',
`total_bp_contribution` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'TOTAL_BP_贡献度',
`mid_per_card` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_信用卡',
`mid_per_pass` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_一码通',
`mid_per_harvest` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_丰收互联',
`mid_per_effect` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_有效客户',
`mid_per_quick_pay` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_快捷支付',
`mid_per_ele_ddc` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_电费代扣',
`mid_per_water_ddc` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_水费代扣',
`mid_per_huashu_ddc` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_华数费代扣',
`mid_per_gas_ddc` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_煤气费代扣',
`mid_per_citizencard` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_市民卡',
`mid_per_fin_man` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_理财业务',
`mid_per_etc` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_etc',
`bp_mid` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'BP_中间业务',
`totoal_bp_relevance` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'TOTAL_BP_关联度',
`apply_amt` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '申请金额',
`bp_loan_amount` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'BP_贷款额度',
`loan_purpose` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '贷款用途',
`biz_proof` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '是否有经营佐证',
`bp_loan_use` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'BP_贷款用途',
`loan_loop` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '循环功能',
`bp_loan_loop` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'BP_循环功能',
`coll_type` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '抵质押类型',
`coll_third_party` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '抵质押物是否三方所有',
`bp_collateral` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'BP_抵押物',
`grey_cust` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '灰名单客户',
`prin_overdue` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '本金逾期',
`interest_overdue` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '利息逾期',
`card_overdue` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '信用卡逾期',
`bp_grey_overdue` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'BP_灰名单与逾期',
`totoal_bp_risk` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'TOTAL_BP_风险度',
`total_bp` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '浮动BP',
`calculate_rate` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '测算利率',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='零售模型输出字段表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `sys_config`
--
DROP TABLE IF EXISTS `sys_config`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `sys_config` (
`config_id` int(5) NOT NULL AUTO_INCREMENT COMMENT '参数主键',
`config_name` varchar(100) DEFAULT '' COMMENT '参数名称',
`config_key` varchar(100) DEFAULT '' COMMENT '参数键名',
`config_value` varchar(500) DEFAULT '' COMMENT '参数键值',
`config_type` char(1) DEFAULT 'N' COMMENT '系统内置Y是 N否',
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`config_id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='参数配置表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `sys_dept`
--
DROP TABLE IF EXISTS `sys_dept`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `sys_dept` (
`dept_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '部门id',
`parent_id` bigint(20) DEFAULT '0' COMMENT '父部门id',
`ancestors` varchar(50) DEFAULT '' COMMENT '祖级列表',
`dept_name` varchar(30) DEFAULT '' COMMENT '部门名称',
`order_num` int(4) DEFAULT '0' COMMENT '显示顺序',
`leader` varchar(20) DEFAULT NULL COMMENT '负责人',
`phone` varchar(11) DEFAULT NULL COMMENT '联系电话',
`email` varchar(50) DEFAULT NULL COMMENT '邮箱',
`status` char(1) DEFAULT '0' COMMENT '部门状态0正常 1停用',
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志0代表存在 2代表删除',
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`dept_id`)
) ENGINE=InnoDB AUTO_INCREMENT=110 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='部门表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `sys_dict_data`
--
DROP TABLE IF EXISTS `sys_dict_data`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `sys_dict_data` (
`dict_code` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '字典编码',
`dict_sort` int(4) DEFAULT '0' COMMENT '字典排序',
`dict_label` varchar(100) DEFAULT '' COMMENT '字典标签',
`dict_value` varchar(100) DEFAULT '' COMMENT '字典键值',
`dict_type` varchar(100) DEFAULT '' COMMENT '字典类型',
`css_class` varchar(100) DEFAULT NULL COMMENT '样式属性(其他样式扩展)',
`list_class` varchar(100) DEFAULT NULL COMMENT '表格回显样式',
`is_default` char(1) DEFAULT 'N' COMMENT '是否默认Y是 N否',
`status` char(1) DEFAULT '0' COMMENT '状态0正常 1停用',
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`dict_code`)
) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='字典数据表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `sys_dict_type`
--
DROP TABLE IF EXISTS `sys_dict_type`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `sys_dict_type` (
`dict_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '字典主键',
`dict_name` varchar(100) DEFAULT '' COMMENT '字典名称',
`dict_type` varchar(100) DEFAULT '' COMMENT '字典类型',
`status` char(1) DEFAULT '0' COMMENT '状态0正常 1停用',
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`dict_id`),
UNIQUE KEY `dict_type` (`dict_type`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='字典类型表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `sys_job`
--
DROP TABLE IF EXISTS `sys_job`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `sys_job` (
`job_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '任务ID',
`job_name` varchar(64) NOT NULL DEFAULT '' COMMENT '任务名称',
`job_group` varchar(64) NOT NULL DEFAULT 'DEFAULT' COMMENT '任务组名',
`invoke_target` varchar(500) NOT NULL COMMENT '调用目标字符串',
`cron_expression` varchar(255) DEFAULT '' COMMENT 'cron执行表达式',
`misfire_policy` varchar(20) DEFAULT '3' COMMENT '计划执行错误策略1立即执行 2执行一次 3放弃执行',
`concurrent` char(1) DEFAULT '1' COMMENT '是否并发执行0允许 1禁止',
`status` char(1) DEFAULT '0' COMMENT '状态0正常 1暂停',
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`remark` varchar(500) DEFAULT '' COMMENT '备注信息',
PRIMARY KEY (`job_id`,`job_name`,`job_group`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='定时任务调度表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `sys_job_log`
--
DROP TABLE IF EXISTS `sys_job_log`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `sys_job_log` (
`job_log_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '任务日志ID',
`job_name` varchar(64) NOT NULL COMMENT '任务名称',
`job_group` varchar(64) NOT NULL COMMENT '任务组名',
`invoke_target` varchar(500) NOT NULL COMMENT '调用目标字符串',
`job_message` varchar(500) DEFAULT NULL COMMENT '日志信息',
`status` char(1) DEFAULT '0' COMMENT '执行状态0正常 1失败',
`exception_info` varchar(2000) DEFAULT '' COMMENT '异常信息',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`job_log_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='定时任务调度日志表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `sys_logininfor`
--
DROP TABLE IF EXISTS `sys_logininfor`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `sys_logininfor` (
`info_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '访问ID',
`user_name` varchar(50) DEFAULT '' COMMENT '用户账号',
`ipaddr` varchar(128) DEFAULT '' COMMENT '登录IP地址',
`login_location` varchar(255) DEFAULT '' COMMENT '登录地点',
`browser` varchar(50) DEFAULT '' COMMENT '浏览器类型',
`os` varchar(50) DEFAULT '' COMMENT '操作系统',
`status` char(1) DEFAULT '0' COMMENT '登录状态0成功 1失败',
`msg` varchar(255) DEFAULT '' COMMENT '提示消息',
`login_time` datetime DEFAULT NULL COMMENT '访问时间',
PRIMARY KEY (`info_id`),
KEY `idx_sys_logininfor_s` (`status`),
KEY `idx_sys_logininfor_lt` (`login_time`)
) ENGINE=InnoDB AUTO_INCREMENT=111 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='系统访问记录';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `sys_menu`
--
DROP TABLE IF EXISTS `sys_menu`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `sys_menu` (
`menu_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '菜单ID',
`menu_name` varchar(50) NOT NULL COMMENT '菜单名称',
`parent_id` bigint(20) DEFAULT '0' COMMENT '父菜单ID',
`order_num` int(4) DEFAULT '0' COMMENT '显示顺序',
`path` varchar(200) DEFAULT '' COMMENT '路由地址',
`component` varchar(255) DEFAULT NULL COMMENT '组件路径',
`query` varchar(255) DEFAULT NULL COMMENT '路由参数',
`route_name` varchar(50) DEFAULT '' COMMENT '路由名称',
`is_frame` int(1) DEFAULT '1' COMMENT '是否为外链0是 1否',
`is_cache` int(1) DEFAULT '0' COMMENT '是否缓存0缓存 1不缓存',
`menu_type` char(1) DEFAULT '' COMMENT '菜单类型M目录 C菜单 F按钮',
`visible` char(1) DEFAULT '0' COMMENT '菜单状态0显示 1隐藏',
`status` char(1) DEFAULT '0' COMMENT '菜单状态0正常 1停用',
`perms` varchar(100) DEFAULT NULL COMMENT '权限标识',
`icon` varchar(100) DEFAULT '#' COMMENT '菜单图标',
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`remark` varchar(500) DEFAULT '' COMMENT '备注',
PRIMARY KEY (`menu_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2003 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='菜单权限表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `sys_notice`
--
DROP TABLE IF EXISTS `sys_notice`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `sys_notice` (
`notice_id` int(4) NOT NULL AUTO_INCREMENT COMMENT '公告ID',
`notice_title` varchar(50) NOT NULL COMMENT '公告标题',
`notice_type` char(1) NOT NULL COMMENT '公告类型1通知 2公告',
`notice_content` longblob COMMENT '公告内容',
`status` char(1) DEFAULT '0' COMMENT '公告状态0正常 1关闭',
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`notice_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='通知公告表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `sys_oper_log`
--
DROP TABLE IF EXISTS `sys_oper_log`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `sys_oper_log` (
`oper_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '日志主键',
`title` varchar(50) DEFAULT '' COMMENT '模块标题',
`business_type` int(2) DEFAULT '0' COMMENT '业务类型0其它 1新增 2修改 3删除',
`method` varchar(200) DEFAULT '' COMMENT '方法名称',
`request_method` varchar(10) DEFAULT '' COMMENT '请求方式',
`operator_type` int(1) DEFAULT '0' COMMENT '操作类别0其它 1后台用户 2手机端用户',
`oper_name` varchar(50) DEFAULT '' COMMENT '操作人员',
`dept_name` varchar(50) DEFAULT '' COMMENT '部门名称',
`oper_url` varchar(255) DEFAULT '' COMMENT '请求URL',
`oper_ip` varchar(128) DEFAULT '' COMMENT '主机地址',
`oper_location` varchar(255) DEFAULT '' COMMENT '操作地点',
`oper_param` varchar(2000) DEFAULT '' COMMENT '请求参数',
`json_result` varchar(2000) DEFAULT '' COMMENT '返回参数',
`status` int(1) DEFAULT '0' COMMENT '操作状态0正常 1异常',
`error_msg` varchar(2000) DEFAULT '' COMMENT '错误消息',
`oper_time` datetime DEFAULT NULL COMMENT '操作时间',
`cost_time` bigint(20) DEFAULT '0' COMMENT '消耗时间',
PRIMARY KEY (`oper_id`),
KEY `idx_sys_oper_log_bt` (`business_type`),
KEY `idx_sys_oper_log_s` (`status`),
KEY `idx_sys_oper_log_ot` (`oper_time`)
) ENGINE=InnoDB AUTO_INCREMENT=125 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='操作日志记录';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `sys_post`
--
DROP TABLE IF EXISTS `sys_post`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `sys_post` (
`post_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '岗位ID',
`post_code` varchar(64) NOT NULL COMMENT '岗位编码',
`post_name` varchar(50) NOT NULL COMMENT '岗位名称',
`post_sort` int(4) NOT NULL COMMENT '显示顺序',
`status` char(1) NOT NULL COMMENT '状态0正常 1停用',
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`post_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='岗位信息表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `sys_role`
--
DROP TABLE IF EXISTS `sys_role`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `sys_role` (
`role_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '角色ID',
`role_name` varchar(30) NOT NULL COMMENT '角色名称',
`role_key` varchar(100) NOT NULL COMMENT '角色权限字符串',
`role_sort` int(4) NOT NULL COMMENT '显示顺序',
`data_scope` char(1) DEFAULT '1' COMMENT '数据范围1全部数据权限 2自定数据权限 3本部门数据权限 4本部门及以下数据权限',
`menu_check_strictly` tinyint(1) DEFAULT '1' COMMENT '菜单树选择项是否关联显示',
`dept_check_strictly` tinyint(1) DEFAULT '1' COMMENT '部门树选择项是否关联显示',
`status` char(1) NOT NULL COMMENT '角色状态0正常 1停用',
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志0代表存在 2代表删除',
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`role_id`)
) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='角色信息表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `sys_role_dept`
--
DROP TABLE IF EXISTS `sys_role_dept`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `sys_role_dept` (
`role_id` bigint(20) NOT NULL COMMENT '角色ID',
`dept_id` bigint(20) NOT NULL COMMENT '部门ID',
PRIMARY KEY (`role_id`,`dept_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='角色和部门关联表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `sys_role_menu`
--
DROP TABLE IF EXISTS `sys_role_menu`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `sys_role_menu` (
`role_id` bigint(20) NOT NULL COMMENT '角色ID',
`menu_id` bigint(20) NOT NULL COMMENT '菜单ID',
PRIMARY KEY (`role_id`,`menu_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='角色和菜单关联表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `sys_user`
--
DROP TABLE IF EXISTS `sys_user`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `sys_user` (
`user_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
`dept_id` bigint(20) DEFAULT NULL COMMENT '部门ID',
`user_name` varchar(30) NOT NULL COMMENT '用户账号',
`nick_name` varchar(30) NOT NULL COMMENT '用户昵称',
`user_type` varchar(2) DEFAULT '00' COMMENT '用户类型00系统用户',
`email` varchar(50) DEFAULT '' COMMENT '用户邮箱',
`phonenumber` varchar(11) DEFAULT '' COMMENT '手机号码',
`sex` char(1) DEFAULT '0' COMMENT '用户性别0男 1女 2未知',
`avatar` varchar(100) DEFAULT '' COMMENT '头像地址',
`password` varchar(100) DEFAULT '' COMMENT '密码',
`status` char(1) DEFAULT '0' COMMENT '账号状态0正常 1停用',
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志0代表存在 2代表删除',
`login_ip` varchar(128) DEFAULT '' COMMENT '最后登录IP',
`login_date` datetime DEFAULT NULL COMMENT '最后登录时间',
`pwd_update_date` datetime DEFAULT NULL COMMENT '密码最后更新时间',
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户信息表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `sys_user_post`
--
DROP TABLE IF EXISTS `sys_user_post`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `sys_user_post` (
`user_id` bigint(20) NOT NULL COMMENT '用户ID',
`post_id` bigint(20) NOT NULL COMMENT '岗位ID',
PRIMARY KEY (`user_id`,`post_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户与岗位关联表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `sys_user_role`
--
DROP TABLE IF EXISTS `sys_user_role`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `sys_user_role` (
`user_id` bigint(20) NOT NULL COMMENT '用户ID',
`role_id` bigint(20) NOT NULL COMMENT '角色ID',
PRIMARY KEY (`user_id`,`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户和角色关联表';
/*!40101 SET character_set_client = @saved_cs_client */;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2026-03-28 9:20:02

View File

@@ -56,4 +56,4 @@ CREATE TABLE `model_corp_output_fields` (
`calculate_rate` VARCHAR(100) COMMENT '测算利率',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='客户贷款利率测算表';
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='客户贷款利率测算表';

View File

@@ -111,4 +111,4 @@ CREATE TABLE IF NOT EXISTS model_retail_output_fields (
-- 主键约束
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='零售模型输出字段表';
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='零售模型输出字段表';

View File

@@ -1,132 +0,0 @@
#!/bin/bash
# 利率定价流程 API 测试脚本
# 使用前请先登录获取 token
BASE_URL="http://localhost:8080"
TOKEN=""
echo "===================================="
echo "利率定价流程 API 测试"
echo "===================================="
echo ""
# 颜色定义
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 如果没有提供 token提示用户登录
if [ -z "$TOKEN" ]; then
echo "${YELLOW}请先使用以下步骤获取 token:${NC}"
echo "1. 访问 http://localhost:8080"
echo "2. 使用 admin/admin123 登录"
echo "3. 打开浏览器开发者工具 (F12)"
echo "4. 在 Network 标签中找到登录请求"
echo "5. 从响应中复制 token 值"
echo ""
echo "然后设置 TOKEN 变量后运行此脚本"
echo ""
echo "或者使用以下方式登录 (需要手动输入验证码):"
echo ""
fi
# 测试函数
test_api() {
local method=$1
local url=$2
local data=$3
local description=$4
echo -n "测试: $description ... "
if [ "$method" = "GET" ]; then
response=$(curl -s -X GET "$BASE_URL$url" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json")
else
response=$(curl -s -X "$method" "$BASE_URL$url" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "$data")
fi
# 检查响应
if echo "$response" | grep -q '"code":200'; then
echo -e "${GREEN}✓ 通过${NC}"
echo " 响应: $(echo "$response" | head -c 200)..."
else
echo -e "${RED}✗ 失败${NC}"
echo " 响应: $response"
fi
echo ""
}
# 测试用例
echo "===================================="
echo "测试用例"
echo "===================================="
echo ""
# 测试 1: 发起利率定价流程
test_api "POST" "/loanPricing/workflow/create" '{
"orgCode": "931000",
"runType": "1",
"custIsn": "CUST001",
"custType": "个人",
"guarType": "信用",
"midPerQuickPay": "true",
"midPerEleDdc": "false",
"midEntEleDdc": "false",
"midEntWaterDdc": "false",
"applyAmt": "50000",
"isCleanEnt": "false",
"hasSettleAcct": "true",
"isManufacturing": "false",
"isAgriGuar": "false",
"isTaxA": "false",
"isAgriLeading": "false",
"loanPurpose": "consumer",
"bizProof": "true",
"collType": "一类",
"collThirdParty": "false",
"loanRate": "4.35",
"custName": "张三",
"idType": "身份证",
"isInclusiveFinance": "true"
}' "发起利率定价流程 (个人客户-信用贷款)"
# 测试 2: 发起利率定价流程 (企业客户)
test_api "POST" "/loanPricing/workflow/create" '{
"orgCode": "931000",
"runType": "1",
"custIsn": "CUST002",
"custType": "企业",
"guarType": "抵押",
"applyAmt": "500000",
"isCleanEnt": "true",
"hasSettleAcct": "true",
"isManufacturing": "true",
"isTaxA": "true",
"loanPurpose": "business",
"collType": "一线",
"collThirdParty": "false",
"loanRate": "3.85",
"custName": "测试科技有限公司",
"idType": "统一社会信用代码",
"isInclusiveFinance": "true"
}' "发起利率定价流程 (企业客户-抵押贷款)"
# 测试 3: 查询流程列表
test_api "GET" "/loanPricing/workflow/list?pageNum=1&pageSize=10" "" "查询流程列表 (第1页)"
# 测试 4: 查询流程列表 (筛选条件)
test_api "GET" "/loanPricing/workflow/list?pageNum=1&pageSize=10&custType=个人" "" "查询流程列表 (筛选:个人客户)"
# 测试 5: 查询流程列表 (按客户名称搜索)
test_api "GET" "/loanPricing/workflow/list?pageNum=1&pageSize=10&custName=张三" "" "查询流程列表 (搜索:张三)"
echo "===================================="
echo "测试完成"
echo "===================================="

View File

@@ -1,141 +0,0 @@
#!/bin/bash
# 利率定价流程执行利率接口测试脚本
# 测试环境: http://localhost:8080
BASE_URL="http://localhost:8080"
LOGIN_URL="${BASE_URL}/login"
WORKFLOW_URL="${BASE_URL}/loanPricing/workflow"
# 测试账号
USERNAME="admin"
PASSWORD="admin123"
# 测试流水号(从数据库获取)
SERIAL_NUM="20260121170730386"
# 颜色输出
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
echo "=========================================="
echo "利率定价流程执行利率接口测试"
echo "=========================================="
echo ""
# 步骤1: 登录获取 Token (使用测试接口,无需验证码)
echo -e "${YELLOW}步骤1: 登录获取 Token (使用测试接口)${NC}"
LOGIN_RESPONSE=$(curl -s -X POST "${BASE_URL}/login/test" \
-H "Content-Type: application/json" \
-d "{\"username\":\"${USERNAME}\",\"password\":\"${PASSWORD}\"}")
TOKEN=$(echo $LOGIN_RESPONSE | grep -o '"token":"[^"]*"' | cut -d'"' -f4)
if [ -z "$TOKEN" ]; then
echo -e "${RED}登录失败,无法获取 Token${NC}"
echo "响应: $LOGIN_RESPONSE"
exit 1
fi
echo -e "${GREEN}登录成功Token: ${TOKEN:0:20}...${NC}"
echo ""
# 步骤2: 查询当前流程详情
echo -e "${YELLOW}步骤2: 查询流程详情 (GET ${WORKFLOW_URL}/${SERIAL_NUM})${NC}"
DETAILS_RESPONSE=$(curl -s -X GET "${WORKFLOW_URL}/${SERIAL_NUM}" \
-H "Authorization: Bearer ${TOKEN}")
echo "$DETAILS_RESPONSE" | python -m json.tool 2>/dev/null || echo "$DETAILS_RESPONSE"
echo ""
# 步骤3: 设定执行利率
echo -e "${YELLOW}步骤3: 设定执行利率 (PUT ${WORKFLOW_URL}/${SERIAL_NUM}/executeRate)${NC}"
SET_RATE_RESPONSE=$(curl -s -X PUT "${WORKFLOW_URL}/${SERIAL_NUM}/executeRate" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"executeRate":"4.20"}')
echo "$SET_RATE_RESPONSE" | python -m json.tool 2>/dev/null || echo "$SET_RATE_RESPONSE"
# 检查响应
CODE=$(echo $SET_RATE_RESPONSE | grep -o '"code":[0-9]*' | cut -d':' -f2)
if [ "$CODE" = "200" ]; then
echo -e "${GREEN}✓ 设定执行利率成功${NC}"
else
echo -e "${RED}✗ 设定执行利率失败${NC}"
fi
echo ""
# 步骤4: 再次查询详情验证 executeRate 字段
echo -e "${YELLOW}步骤4: 再次查询详情验证 executeRate 字段${NC}"
DETAILS_RESPONSE2=$(curl -s -X GET "${WORKFLOW_URL}/${SERIAL_NUM}" \
-H "Authorization: Bearer ${TOKEN}")
echo "$DETAILS_RESPONSE2" | python -m json.tool 2>/dev/null || echo "$DETAILS_RESPONSE2"
# 检查 executeRate 字段
EXECUTE_RATE=$(echo $DETAILS_RESPONSE2 | grep -o '"executeRate":"[^"]*"' | cut -d'"' -f4)
if [ "$EXECUTE_RATE" = "4.20" ]; then
echo -e "${GREEN}✓ executeRate 字段正确返回: ${EXECUTE_RATE}${NC}"
else
echo -e "${RED}✗ executeRate 字段值不正确${NC}"
fi
echo ""
# 步骤5: 更新执行利率(验证可修改)
echo -e "${YELLOW}步骤5: 更新执行利率为 3.85${NC}"
UPDATE_RATE_RESPONSE=$(curl -s -X PUT "${WORKFLOW_URL}/${SERIAL_NUM}/executeRate" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"executeRate":"3.85"}')
echo "$UPDATE_RATE_RESPONSE" | python -m json.tool 2>/dev/null || echo "$UPDATE_RATE_RESPONSE"
CODE=$(echo $UPDATE_RATE_RESPONSE | grep -o '"code":[0-9]*' | cut -d':' -f2)
if [ "$CODE" = "200" ]; then
echo -e "${GREEN}✓ 更新执行利率成功${NC}"
else
echo -e "${RED}✗ 更新执行利率失败${NC}"
fi
echo ""
# 步骤6: 测试不存在的流水号
echo -e "${YELLOW}步骤6: 测试不存在的流水号 (404场景)${NC}"
NOT_FOUND_RESPONSE=$(curl -s -X PUT "${WORKFLOW_URL}/99999999999999999/executeRate" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"executeRate":"4.20"}')
echo "$NOT_FOUND_RESPONSE" | python -m json.tool 2>/dev/null || echo "$NOT_FOUND_RESPONSE"
CODE=$(echo $NOT_FOUND_RESPONSE | grep -o '"code":[0-9]*' | cut -d':' -f2)
MSG=$(echo $NOT_FOUND_RESPONSE | grep -o '"msg":"[^"]*"' | cut -d'"' -f4)
if [ "$CODE" != "200" ]; then
echo -e "${GREEN}✓ 不存在的流水号正确返回错误: ${MSG}${NC}"
else
echo -e "${RED}✗ 应该返回错误但返回了成功${NC}"
fi
echo ""
# 步骤7: 测试空值
echo -e "${YELLOW}步骤7: 测试设定空值${NC}"
NULL_RATE_RESPONSE=$(curl -s -X PUT "${WORKFLOW_URL}/${SERIAL_NUM}/executeRate" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"executeRate":null}')
echo "$NULL_RATE_RESPONSE" | python -m json.tool 2>/dev/null || echo "$NULL_RATE_RESPONSE"
CODE=$(echo $NULL_RATE_RESPONSE | grep -o '"code":[0-9]*' | cut -d':' -f2)
if [ "$CODE" = "200" ]; then
echo -e "${GREEN}✓ 空值设定成功${NC}"
else
echo -e "${YELLOW}空值设定响应: ${MSG}${NC}"
fi
echo ""
echo "=========================================="
echo "测试完成"
echo "=========================================="