diff --git a/.gitignore b/.gitignore
index 51f3bb8..2be6f5e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -47,3 +47,6 @@ nbdist/
!*/build/*.xml
logs/
+.playwright-cli/
+ruoyi-ui/tests
+*/src/test
\ No newline at end of file
diff --git a/doc/2026-04-15-Breadcrumb重复key修复前端实施记录.md b/doc/2026-04-15-Breadcrumb重复key修复前端实施记录.md
new file mode 100644
index 0000000..3d159ee
--- /dev/null
+++ b/doc/2026-04-15-Breadcrumb重复key修复前端实施记录.md
@@ -0,0 +1,90 @@
+# Breadcrumb 重复 key 修复前端实施记录
+
+## 1. 实际改动内容
+
+### 1.1 修复 Breadcrumb 重复 key 告警
+
+修改文件:
+
+- `ruoyi-ui/src/components/Breadcrumb/index.vue`
+- `ruoyi-ui/src/components/Breadcrumb/utils.js`
+
+改动内容:
+
+- 将 Breadcrumb 列表项的 `key` 生成逻辑从直接使用 `item.path` 调整为统一调用 `buildBreadcrumbItemKey`
+- 新增 `buildBreadcrumbItemKey(item, index)` 工具方法,使用 `path + title + index` 组合生成稳定且唯一的 key
+- 保持现有面包屑展示逻辑不变,不调整路由结构、不修改首页与当前页的展示顺序
+
+根因说明:
+
+- 当前项目的 Breadcrumb 会在非首页场景外额外插入一个 `首页` 面包屑,路径固定为 `'/index'`
+- 当当前页面本身也对应 `'/index'` 时,原逻辑使用 `item.path` 作为 `transition-group` 的 key,会同时生成两个 `'/index'`
+- Vue 因此抛出 `Duplicate keys detected: '/index'`
+
+### 1.2 增加最小回归测试
+
+修改文件:
+
+- `ruoyi-ui/tests/breadcrumb-duplicate-key.test.js`
+
+改动内容:
+
+- 新增最小 Node 断言脚本
+- 校验当两个 Breadcrumb 条目 path 同为 `'/index'` 时,生成的 key 仍然唯一
+- 锁定本次问题,避免后续调整 Breadcrumb 时再次引入相同告警
+
+## 2. 验证结果
+
+### 2.1 Node 版本
+
+项目中未提供 `.nvmrc`,因此未能直接执行 `nvm use` 自动切换。
+
+实际使用版本:
+
+- `nvm use 14.21.3`
+
+### 2.2 测试命令
+
+已执行:
+
+- `cd ruoyi-ui && source ~/.nvm/nvm.sh && nvm use 14.21.3 >/dev/null && node tests/breadcrumb-duplicate-key.test.js`
+
+结果:
+
+- 测试通过
+- 输出 `breadcrumb duplicate key assertions passed`
+
+### 2.3 构建命令
+
+已执行:
+
+- `cd ruoyi-ui && source ~/.nvm/nvm.sh && nvm use 14.21.3 >/dev/null && npm run build:prod`
+
+结果:
+
+- 构建成功
+- 输出 `DONE Build complete. The dist directory is ready to be deployed.`
+
+### 2.4 构建告警
+
+存在 webpack 资源体积告警:
+
+- `asset size limit`
+- `entrypoint size limit`
+
+说明:
+
+- 这些是现有项目静态资源体积告警
+- 本次 Breadcrumb 修复未引入新的构建错误或新的语法告警
+
+## 3. 影响范围
+
+- 仅涉及前端 Breadcrumb 组件
+- 未修改后端代码
+- 未修改贷款定价业务字段逻辑
+
+## 4. 当前结论
+
+- `Duplicate keys detected: '/index'` 的 Breadcrumb 告警已修复
+- 修复方式限定在组件 key 生成逻辑,属于最短路径处理
+- 前端回归测试与生产构建均已通过
diff --git a/doc/2026-04-15-上虞对公展示指标对齐前端实施计划.md b/doc/2026-04-15-上虞对公展示指标对齐前端实施计划.md
new file mode 100644
index 0000000..041cb85
--- /dev/null
+++ b/doc/2026-04-15-上虞对公展示指标对齐前端实施计划.md
@@ -0,0 +1,26 @@
+# 2026-04-15 上虞对公展示指标对齐前端实施计划
+
+## 改动内容
+- 对齐 [CorporateCreateDialog.vue](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-ui/src/views/loanPricing/workflow/components/CorporateCreateDialog.vue) 的对公新增弹窗:
+ - 新增 `repayMethod`
+ - `loanTerm` 改为 `1-6` 年下拉
+ - `collType` 改为 `一类/二类/三类/四类`
+ - 对外提交字段改为 `isTradeBuildEnt`
+ - `isGreenLoan`、`isTradeBuildEnt`、`collThirdParty` 统一提交 `0/1`
+ - 移除 `isAgriGuar`、`isTechEnt`
+- 对齐 [CorporateWorkflowDetail.vue](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-ui/src/views/loanPricing/workflow/components/CorporateWorkflowDetail.vue) 的流程详情录入字段展示:
+ - 新增 `还款方式`
+ - `贷款期限` 改为 `借款期限`
+ - 保留 `绿色贷款`、`贸易和建筑业企业`、`抵质押类型`、`抵质押物是否三方所有`
+ - 移除 `省农担担保贷款`、`科技型企业`
+- 对齐 [ModelOutputDisplay.vue](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-ui/src/views/loanPricing/workflow/components/ModelOutputDisplay.vue) 的企业模型输出展示口径:
+ - 展示 `repayMethod`、`isTradeBuildEnt`
+ - 不再展示 `省农担担保贷款`、`科技型企业`
+- 新增/更新前端静态断言:
+ - [corporate-create-input-params.test.js](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-ui/tests/corporate-create-input-params.test.js)
+ - [corporate-display-fields.test.js](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-ui/tests/corporate-display-fields.test.js)
+
+## 验证记录
+- `source ~/.nvm/nvm.sh && nvm use 14 >/dev/null && node tests/corporate-create-input-params.test.js`
+- `source ~/.nvm/nvm.sh && nvm use 14 >/dev/null && node tests/corporate-display-fields.test.js`
+- `source ~/.nvm/nvm.sh && nvm use 14 >/dev/null && npm run build:prod`
diff --git a/doc/2026-04-15-上虞对公展示指标对齐后端实施计划.md b/doc/2026-04-15-上虞对公展示指标对齐后端实施计划.md
new file mode 100644
index 0000000..0884d83
--- /dev/null
+++ b/doc/2026-04-15-上虞对公展示指标对齐后端实施计划.md
@@ -0,0 +1,39 @@
+# 2026-04-15 上虞对公展示指标对齐后端实施计划
+
+## 改动内容
+- 对齐对公创建接口 DTO 与模型调用 DTO:
+ - [CorporateLoanPricingCreateDTO.java](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/CorporateLoanPricingCreateDTO.java)
+ - [ModelInvokeDTO.java](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/ModelInvokeDTO.java)
+ - 新增 `repayMethod`
+ - 对外字段改为 `isTradeBuildEnt`
+ - `loanTerm` 校验为 `1-6`
+ - `collType` 校验为 `一类/二类/三类/四类`
+- 对齐流程实体、详情出参和模型输出镜像:
+ - [LoanPricingWorkflow.java](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/entity/LoanPricingWorkflow.java)
+ - [ModelCorpOutputFields.java](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/entity/ModelCorpOutputFields.java)
+ - [LoanPricingConverter.java](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/util/LoanPricingConverter.java)
+ - [LoanPricingModelService.java](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/LoanPricingModelService.java)
+ - [LoanPricingWorkflowServiceImpl.java](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/impl/LoanPricingWorkflowServiceImpl.java)
+ - 内部继续复用 `isTradeConstruction` 落库,外部统一返回 `isTradeBuildEnt`
+ - `isAgriGuar`、`isTechEnt` 从对外 JSON 隐藏
+ - 企业模型输出补充 `repayMethod`、`isTradeBuildEnt` 展示镜像
+- 对齐 mock 与 SQL 资产:
+ - [corp_output.json](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-loan-pricing/src/main/resources/data/corp_output.json)
+ - [loan_pricing_workflow.sql](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/sql/loan_pricing_workflow.sql)
+ - [loan_pricing_schema_20260328.sql](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/sql/loan_pricing_schema_20260328.sql)
+ - [loan_pricing_prod_init_20260331.sql](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/sql/loan_pricing_prod_init_20260331.sql)
+ - [loan_pricing_required_data_20260328.sql](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/sql/loan_pricing_required_data_20260328.sql)
+ - [loan_pricing_alter_20260415_repay_method.sql](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/sql/loan_pricing_alter_20260415_repay_method.sql)
+ - [test_corporate_create.http](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/test_api/test_corporate_create.http)
+ - [test_corporate_create.sh](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/test_api/test_corporate_create.sh)
+ - `loan_pricing_workflow` 增加 `repay_method`
+ - mock 数据和接口样例统一为 Excel 字段名与 `0/1` 口径
+ - 补充独立增量 SQL,便于其他环境按最小影响同步结构
+- 新增/更新后端定向单测:
+ - [LoanPricingModelServiceCorporateParamsTest.java](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/LoanPricingModelServiceCorporateParamsTest.java)
+ - [LoanPricingModelServiceTest.java](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/LoanPricingModelServiceTest.java)
+ - [LoanPricingWorkflowServiceImplTest.java](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/impl/LoanPricingWorkflowServiceImplTest.java)
+ - [LoanPricingConverterTest.java](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/util/LoanPricingConverterTest.java)
+
+## 验证记录
+- `mvn -pl ruoyi-loan-pricing -am -Dtest=LoanPricingModelServiceCorporateParamsTest,LoanPricingModelServiceTest,LoanPricingWorkflowServiceImplTest,LoanPricingConverterTest -Dsurefire.failIfNoSpecifiedTests=false test`
diff --git a/doc/2026-04-15-审计字段自动填充后端实施记录.md b/doc/2026-04-15-审计字段自动填充后端实施记录.md
new file mode 100644
index 0000000..b7c6612
--- /dev/null
+++ b/doc/2026-04-15-审计字段自动填充后端实施记录.md
@@ -0,0 +1,22 @@
+# 2026-04-15 审计字段自动填充后端实施记录
+
+## 背景
+
+- 贷款定价流程实体已经声明了 MyBatis-Plus 的 `FieldFill`,但当前分支缺少迁移源分支中的统一审计填充处理器。
+- 导致 `insert` 和 `updateById` 执行时,`createBy`、`createTime`、`updateBy`、`updateTime` 不会自动写入或刷新。
+
+## 本次改动
+
+- 新增 [MyMetaHandler.java](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-framework/src/main/java/com/ruoyi/framework/config/handler/MyMetaHandler.java),恢复与迁移源分支一致的统一审计填充逻辑。
+- 审计人格式保持与源分支一致,统一写入 `昵称-用户名`。
+- 新增 [MyMetaHandlerTest.java](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-framework/src/test/java/com/ruoyi/framework/config/handler/MyMetaHandlerTest.java),覆盖插入填充与更新填充两个核心场景。
+
+## 验证结果
+
+- 执行 `mvn -pl ruoyi-framework -am -Dtest=MyMetaHandlerTest -Dsurefire.failIfNoSpecifiedTests=false test`,通过。
+- 执行 `mvn -pl ruoyi-loan-pricing -am -Dtest=MyMetaHandlerTest,LoanPricingWorkflowServiceImplTest,LoanPricingModelServiceTest,LoanPricingModelServiceCorporateParamsTest,LoanPricingModelServicePersonalParamsTest -Dsurefire.failIfNoSpecifiedTests=false test`,通过。
+
+## 影响说明
+
+- 所有使用 MyBatis-Plus 自动填充并声明对应字段的实体,在当前登录上下文下执行新增和更新时,都会自动维护审计字段。
+- 本次未改动贷款定价业务入参、SQL 结构和前端页面行为。
diff --git a/doc/2026-04-15-对公流程详情测算结果与风险分析分组调整前端实施记录.md b/doc/2026-04-15-对公流程详情测算结果与风险分析分组调整前端实施记录.md
new file mode 100644
index 0000000..03552b5
--- /dev/null
+++ b/doc/2026-04-15-对公流程详情测算结果与风险分析分组调整前端实施记录.md
@@ -0,0 +1,24 @@
+# 对公流程详情测算结果与风险分析分组调整前端实施记录
+
+## 变更日期
+- 2026-04-15
+
+## 变更范围
+- 前端页面:`ruoyi-ui/src/views/loanPricing/workflow/components/ModelOutputDisplay.vue`
+- 前端校验:`ruoyi-ui/tests/corporate-create-input-params.test.js`
+- 前端校验:`ruoyi-ui/tests/corporate-display-fields.test.js`
+
+## 实施内容
+- 将对公流程详情“模型输出”卡片中的“测算结果”从原“风险度与测算结果”合并分组中拆出。
+- 按页面要求将对公模型输出分组顺序调整为“基本信息 → 测算结果 → 忠诚度分析 → 贡献度分析 → 关联度分析 → 风险分析”。
+- 保留“风险分析”在模型输出卡片末尾,仅调整展示分组,不修改接口字段、父组件传参和格式化逻辑。
+- 补充前端断言,校验对公模型输出存在独立“测算结果”“风险分析”标题,且不再保留“风险度与测算结果”合并标题。
+
+## 影响说明
+- 本次仅涉及前端详情页展示层,不涉及后端接口、数据库脚本和模型测算逻辑。
+- 对公流程详情页中,用户可在基本信息后直接查看测算结果,风险分析独立展示且位于模型输出末尾。
+
+## 验证结果
+- 执行 `node ruoyi-ui/tests/corporate-create-input-params.test.js`,断言通过。
+- 执行 `node ruoyi-ui/tests/corporate-display-fields.test.js`,断言通过。
+- 执行 `cd ruoyi-ui && nvm use 14.21.3 && npm run build:prod`,前端生产构建通过。
diff --git a/doc/2026-04-15-开发库补列SQL落盘实施记录.md b/doc/2026-04-15-开发库补列SQL落盘实施记录.md
new file mode 100644
index 0000000..be0dcf8
--- /dev/null
+++ b/doc/2026-04-15-开发库补列SQL落盘实施记录.md
@@ -0,0 +1,16 @@
+# 2026-04-15 开发库补列 SQL 落盘实施记录
+
+## 修改内容
+- 将开发库已执行的对公字段补列 SQL 整理并保存到 `sql/loan_pricing_alter_20260415_repay_method.sql`。
+- 在原有 `loan_pricing_workflow.repay_method` 基础上,补充 `model_corp_output_fields` 的以下字段变更语句:
+ - `repay_method`
+ - `is_trade_build_ent`
+ - `loan_rate_history`
+ - `min_rate_product`
+ - `smooth_range`
+ - `final_calculate_rate`
+ - `reference_rate`
+
+## 结果
+- 现有 SQL 文件已可直接用于同步开发库本次字段补齐变更。
+- 文件内容与本次实际执行到开发库的语句保持一致。
diff --git a/doc/~$上虞对公利率测算_上传字段与展示字段 .xlsx b/doc/~$上虞对公利率测算_上传字段与展示字段 .xlsx
new file mode 100644
index 0000000..3c3a794
Binary files /dev/null and b/doc/~$上虞对公利率测算_上传字段与展示字段 .xlsx differ
diff --git a/doc/上虞对公利率测算_上传字段与展示字段 .xlsx b/doc/上虞对公利率测算_上传字段与展示字段 .xlsx
new file mode 100644
index 0000000..679fcd9
Binary files /dev/null and b/doc/上虞对公利率测算_上传字段与展示字段 .xlsx differ
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/handler/MyMetaHandler.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/handler/MyMetaHandler.java
new file mode 100644
index 0000000..29ac851
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/handler/MyMetaHandler.java
@@ -0,0 +1,34 @@
+package com.ruoyi.framework.config.handler;
+
+import java.util.Date;
+
+import org.apache.ibatis.reflection.MetaObject;
+import org.springframework.stereotype.Component;
+
+import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
+import com.ruoyi.common.utils.SecurityUtils;
+
+/**
+ * 实体类自动配置创建日期和更新日期
+ */
+@Component
+public class MyMetaHandler implements MetaObjectHandler
+{
+ @Override
+ public void insertFill(MetaObject metaObject)
+ {
+ String auditUser = SecurityUtils.getLoginUser().getUser().getNickName() + '-' + SecurityUtils.getUsername();
+ this.setFieldValByName("createBy", auditUser, metaObject);
+ this.setFieldValByName("createTime", new Date(), metaObject);
+ this.setFieldValByName("updateBy", auditUser, metaObject);
+ this.setFieldValByName("updateTime", new Date(), metaObject);
+ }
+
+ @Override
+ public void updateFill(MetaObject metaObject)
+ {
+ String auditUser = SecurityUtils.getLoginUser().getUser().getNickName() + '-' + SecurityUtils.getUsername();
+ this.setFieldValByName("updateBy", auditUser, metaObject);
+ this.setFieldValByName("updateTime", new Date(), metaObject);
+ }
+}
diff --git a/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/CorporateLoanPricingCreateDTO.java b/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/CorporateLoanPricingCreateDTO.java
index 2675651..6ea5326 100644
--- a/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/CorporateLoanPricingCreateDTO.java
+++ b/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/CorporateLoanPricingCreateDTO.java
@@ -19,12 +19,18 @@ public class CorporateLoanPricingCreateDTO implements Serializable {
@NotBlank(message = "客户内码不能为空")
private String custIsn;
+ private String custType;
+
private String custName;
private String idType;
private String idNum;
+ @NotBlank(message = "还款方式不能为空")
+ @Pattern(regexp = "^(分期|不分期)$", message = "还款方式必须是:分期、不分期之一")
+ private String repayMethod;
+
@NotBlank(message = "担保方式不能为空")
@Pattern(regexp = "^(信用|保证|抵押|质押)$", message = "担保方式必须是:信用、保证、抵押、质押之一")
private String guarType;
@@ -32,16 +38,16 @@ public class CorporateLoanPricingCreateDTO implements Serializable {
@NotBlank(message = "申请金额不能为空")
private String applyAmt;
+ @NotBlank(message = "借款期限不能为空")
+ @Pattern(regexp = "^[1-6]$", message = "借款期限必须是 1 到 6 年")
private String loanTerm;
- private String isAgriGuar;
-
private String isGreenLoan;
- private String isTechEnt;
-
- private String isTradeConstruction;
+ private String isTradeBuildEnt;
+ @NotBlank(message = "抵质押类型不能为空")
+ @Pattern(regexp = "^(一类|二类|三类|四类)$", message = "抵质押类型必须是:一类、二类、三类、四类之一")
private String collType;
private String collThirdParty;
diff --git a/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/ModelInvokeDTO.java b/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/ModelInvokeDTO.java
index d65bbfb..ac2a94f 100644
--- a/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/ModelInvokeDTO.java
+++ b/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/ModelInvokeDTO.java
@@ -43,6 +43,12 @@ public class ModelInvokeDTO {
*/
private String guarType;
+ /**
+ * 还款方式(必填)
+ * 可选值:分期/不分期
+ */
+ private String repayMethod;
+
/**
* 中间业务_个人_快捷支付(非必填)
* 可选值:true/false
@@ -103,6 +109,18 @@ public class ModelInvokeDTO {
*/
private String isAgriGuar;
+ /**
+ * 绿色贷款(非必填)
+ * 可选值:0/1
+ */
+ private String isGreenLoan;
+
+ /**
+ * 贸易和建筑业企业(非必填)
+ * 可选值:0/1
+ */
+ private String isTradeBuildEnt;
+
/**
* 是否纳税信用等级A级(非必填)
* 可选值:true/false
@@ -137,7 +155,7 @@ public class ModelInvokeDTO {
/**
* 抵质押类型(非必填)
- * 可选值:一类/二类/三类
+ * 可选值:一类/二类/三类/四类
*/
private String collType;
diff --git a/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/entity/LoanPricingWorkflow.java b/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/entity/LoanPricingWorkflow.java
index f64a162..3c82e5f 100644
--- a/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/entity/LoanPricingWorkflow.java
+++ b/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/entity/LoanPricingWorkflow.java
@@ -1,6 +1,7 @@
package com.ruoyi.loanpricing.domain.entity;
import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import javax.validation.constraints.NotBlank;
@@ -48,6 +49,9 @@ public class LoanPricingWorkflow implements Serializable
@NotBlank(message = "担保方式不能为空")
private String guarType;
+ /** 还款方式: 分期/不分期 */
+ private String repayMethod;
+
/** 中间业务_个人_快捷支付: true/false */
private String midPerQuickPay;
@@ -65,7 +69,7 @@ public class LoanPricingWorkflow implements Serializable
private String applyAmt;
/**
- * 贷款期限
+ * 借款期限(年)
*/
private String loanTerm;
@@ -79,13 +83,21 @@ public class LoanPricingWorkflow implements Serializable
private String isManufacturing;
/** 省农担担保贷款: true/false */
+ @JsonIgnore
private String isAgriGuar;
/**
* 贸易和建筑业企业标识: true/false
*/
+ @JsonIgnore
private String isTradeConstruction;
+ /**
+ * 贸易和建筑业企业标识: 0/1
+ */
+ @TableField(exist = false)
+ private String isTradeBuildEnt;
+
/**
* 绿色贷款: true/false
*/
@@ -94,6 +106,7 @@ public class LoanPricingWorkflow implements Serializable
/**
* 科技型企业: true/false
*/
+ @JsonIgnore
private String isTechEnt;
/** 是否纳税信用等级A级: true/false */
@@ -111,7 +124,7 @@ public class LoanPricingWorkflow implements Serializable
/** 循环功能: true/false */
private String loanLoop;
- /** 抵质押类型: 一线/一类/二类 */
+ /** 抵质押类型: 一类/二类/三类/四类 */
private String collType;
/** 抵质押物是否三方所有: true/false */
diff --git a/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/entity/ModelCorpOutputFields.java b/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/entity/ModelCorpOutputFields.java
index c7ec5ad..a5f234a 100644
--- a/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/entity/ModelCorpOutputFields.java
+++ b/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/entity/ModelCorpOutputFields.java
@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
+import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import java.util.Date;
@@ -31,6 +32,9 @@ public class ModelCorpOutputFields {
private String idType;
// 证件号码
private String idNum;
+ // 还款方式
+ @TableField(exist = false)
+ private String repayMethod;
// 基准利率
private String baseLoanRate;
// 我行首贷客户
@@ -79,12 +83,14 @@ public class ModelCorpOutputFields {
private String isCleanEnt;
// 开立基本结算账户
private String hasSettleAcct;
+ // 贸易和建筑业企业
+ @TableField(exist = false)
+ private String isTradeBuildEnt;
// 省农担担保贷款
+ @JsonIgnore
private String isAgriGuar;
// 绿色贷款
private String isGreenLoan;
- // 科技型企业
- private String isTechEnt;
// BP_企业客户类别
private String bpEntType;
// TOTAL_BP_关联度
@@ -119,6 +125,16 @@ public class ModelCorpOutputFields {
private String totalBp;
// 测算利率
private String calculateRate;
+ // 历史利率
+ private String loanRateHistory;
+ // 产品最低利率下限
+ private String minRateProduct;
+ // 平滑幅度
+ private String smoothRange;
+ // 最终测算利率
+ private String finalCalculateRate;
+ // 参考利率
+ private String referenceRate;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
diff --git a/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/LoanPricingModelService.java b/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/LoanPricingModelService.java
index c4b457e..93c8338 100644
--- a/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/LoanPricingModelService.java
+++ b/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/LoanPricingModelService.java
@@ -59,10 +59,15 @@ public class LoanPricingModelService {
}
ModelInvokeDTO modelInvokeDTO = new ModelInvokeDTO();
BeanUtils.copyProperties(loanPricingWorkflow, modelInvokeDTO);
+ modelInvokeDTO.setIsTradeBuildEnt(toZeroOne(loanPricingWorkflow.getIsTradeConstruction()));
if ("个人".equals(loanPricingWorkflow.getCustType()))
{
normalizePersonalModelInvokeDTO(modelInvokeDTO);
}
+ if ("企业".equals(loanPricingWorkflow.getCustType()))
+ {
+ normalizeCorporateModelInvokeDTO(modelInvokeDTO);
+ }
JSONObject response = modelService.invokeModel(modelInvokeDTO);
if (loanPricingWorkflow.getCustType().equals("个人")){
// 个人模型
@@ -94,6 +99,13 @@ public class LoanPricingModelService {
modelInvokeDTO.setCollThirdParty(toZeroOne(modelInvokeDTO.getCollThirdParty()));
}
+ private void normalizeCorporateModelInvokeDTO(ModelInvokeDTO modelInvokeDTO)
+ {
+ modelInvokeDTO.setIsGreenLoan(toZeroOne(modelInvokeDTO.getIsGreenLoan()));
+ modelInvokeDTO.setIsTradeBuildEnt(toZeroOne(modelInvokeDTO.getIsTradeBuildEnt()));
+ modelInvokeDTO.setCollThirdParty(toZeroOne(modelInvokeDTO.getCollThirdParty()));
+ }
+
private String toZeroOne(String value)
{
if ("true".equals(value) || "1".equals(value))
diff --git a/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/impl/LoanPricingWorkflowServiceImpl.java b/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/impl/LoanPricingWorkflowServiceImpl.java
index 6d80edb..e17838e 100644
--- a/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/impl/LoanPricingWorkflowServiceImpl.java
+++ b/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/impl/LoanPricingWorkflowServiceImpl.java
@@ -78,6 +78,8 @@ public class LoanPricingWorkflowServiceImpl implements ILoanPricingWorkflowServi
{
loanPricingWorkflow.setRunType("1");
}
+ loanPricingWorkflow.setCustType("企业".equals(loanPricingWorkflow.getCustType()) ? "企业" : loanPricingWorkflow.getCustType());
+ loanPricingWorkflow.setIsTradeBuildEnt(loanPricingWorkflow.getIsTradeConstruction());
loanPricingWorkflow.setCustName(sensitiveFieldCryptoService.encrypt(loanPricingWorkflow.getCustName()));
loanPricingWorkflow.setIdNum(sensitiveFieldCryptoService.encrypt(loanPricingWorkflow.getIdNum()));
@@ -163,6 +165,7 @@ public class LoanPricingWorkflowServiceImpl implements ILoanPricingWorkflowServi
String plainIdNum = sensitiveFieldCryptoService.decrypt(loanPricingWorkflow.getIdNum());
loanPricingWorkflow.setCustName(loanPricingSensitiveDisplayService.maskCustName(plainCustName));
loanPricingWorkflow.setIdNum(loanPricingSensitiveDisplayService.maskIdNum(plainIdNum));
+ loanPricingWorkflow.setIsTradeBuildEnt(loanPricingWorkflow.getIsTradeConstruction());
loanPricingWorkflowVO.setLoanPricingWorkflow(loanPricingWorkflow);
if (Objects.nonNull(loanPricingWorkflow.getModelOutputId())){
@@ -180,6 +183,8 @@ public class LoanPricingWorkflowServiceImpl implements ILoanPricingWorkflowServi
if (Objects.nonNull(modelCorpOutputFields))
{
maskModelCorpOutputBasicInfo(modelCorpOutputFields);
+ modelCorpOutputFields.setRepayMethod(loanPricingWorkflow.getRepayMethod());
+ modelCorpOutputFields.setIsTradeBuildEnt(loanPricingWorkflow.getIsTradeBuildEnt());
loanPricingWorkflow.setLoanRate(modelCorpOutputFields.getCalculateRate());
}
loanPricingWorkflowVO.setModelCorpOutputFields(modelCorpOutputFields);
diff --git a/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/util/LoanPricingConverter.java b/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/util/LoanPricingConverter.java
index ca0715e..873f8aa 100644
--- a/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/util/LoanPricingConverter.java
+++ b/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/util/LoanPricingConverter.java
@@ -52,15 +52,15 @@ public class LoanPricingConverter {
entity.setCustName(dto.getCustName());
entity.setIdType(dto.getIdType());
entity.setIdNum(dto.getIdNum());
+ entity.setRepayMethod(dto.getRepayMethod());
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.setIsTradeConstruction(dto.getIsTradeBuildEnt());
+ entity.setIsTradeBuildEnt(dto.getIsTradeBuildEnt());
entity.setLoanTerm(dto.getLoanTerm());
return entity;
}
diff --git a/ruoyi-loan-pricing/src/main/resources/data/corp_output.json b/ruoyi-loan-pricing/src/main/resources/data/corp_output.json
index 5752edc..65e8f93 100644
--- a/ruoyi-loan-pricing/src/main/resources/data/corp_output.json
+++ b/ruoyi-loan-pricing/src/main/resources/data/corp_output.json
@@ -4,11 +4,12 @@
"tokenId": "17364055486305E7F4722M8IPFWNL8TOBEB",
"mappingOutputFields": {
"custIsn": "CUST20260121001",
- "custType": "企业客户",
- "guarType": "抵押担保",
+ "custType": "企业",
+ "guarType": "抵押",
"custName": "北京智联科技有限公司",
"idType": "营业执照",
"idNum": "91110108MA00XXXXXX",
+ "repayMethod": "分期",
"baseLoanRate": "3.45",
"isFirstLoan": "N",
"faithDay": "730",
@@ -33,17 +34,16 @@
"bpPayroll": "4.1",
"isCleanEnt": "Y",
"hasSettleAcct": "Y",
- "isAgriGuar": "N",
- "isGreenLoan": "Y",
- "isTechEnt": "Y",
+ "isGreenLoan": "1",
+ "isTradeBuildEnt": "0",
"bpEntType": "7.5",
"totoalBpRelevance": "9.2",
- "loanTerm": "36",
+ "loanTerm": "6",
"bpLoanTerm": "3.3",
- "applyAmt": "5000000.00",
+ "applyAmt": "1000000.00",
"bpLoanAmount": "5.8",
- "collType": "房产抵押",
- "collThirdParty": "N",
+ "collType": "四类",
+ "collThirdParty": "1",
"bpCollateral": "4.5",
"greyCust": "N",
"prinOverdue": "N",
@@ -65,4 +65,4 @@
"workflowVersion": 14,
"callTime": 1736405548630,
"status": 1
-}
\ No newline at end of file
+}
diff --git a/ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/LoanPricingModelServiceTest.java b/ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/LoanPricingModelServiceTest.java
index e983273..31e3bf5 100644
--- a/ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/LoanPricingModelServiceTest.java
+++ b/ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/LoanPricingModelServiceTest.java
@@ -87,4 +87,30 @@ class LoanPricingModelServiceTest
!Objects.equals("张三", entity.getCustName())
&& !Objects.equals("110101199001011234", entity.getIdNum())));
}
+
+ @Test
+ void shouldSendCorporateRepayMethodAndTradeBuildFlagToModel()
+ {
+ LoanPricingWorkflow workflow = new LoanPricingWorkflow();
+ workflow.setId(3L);
+ workflow.setCustType("企业");
+ workflow.setCustName("cipher-name");
+ workflow.setIdNum("cipher-id");
+ workflow.setRepayMethod("分期");
+ workflow.setIsTradeConstruction("1");
+
+ JSONObject response = new JSONObject();
+ response.put("calculateRate", "4.10");
+
+ when(loanPricingWorkflowMapper.selectById(3L)).thenReturn(workflow);
+ when(sensitiveFieldCryptoService.decrypt("cipher-name")).thenReturn("上虞测试企业");
+ when(sensitiveFieldCryptoService.decrypt("cipher-id")).thenReturn("91330000123456789X");
+ when(modelService.invokeModel(any())).thenReturn(response);
+
+ loanPricingModelService.invokeModelAsync(3L);
+
+ verify(modelService).invokeModel(argThat((ModelInvokeDTO dto) ->
+ Objects.equals("分期", dto.getRepayMethod())
+ && Objects.equals("1", dto.getIsTradeBuildEnt())));
+ }
}
diff --git a/ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/impl/LoanPricingWorkflowServiceImplTest.java b/ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/impl/LoanPricingWorkflowServiceImplTest.java
index 15e0bcc..29f4be1 100644
--- a/ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/impl/LoanPricingWorkflowServiceImplTest.java
+++ b/ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/impl/LoanPricingWorkflowServiceImplTest.java
@@ -253,4 +253,33 @@ class LoanPricingWorkflowServiceImplTest
assertEquals("测试****公司", result.getModelCorpOutputFields().getCustName());
assertEquals("91*************00X", result.getModelCorpOutputFields().getIdNum());
}
+
+ @Test
+ void shouldReturnCorporateDisplaySheetFieldsInWorkflowDetail()
+ {
+ LoanPricingWorkflow workflow = new LoanPricingWorkflow();
+ workflow.setSerialNum("C20260415001");
+ workflow.setCustType("企业");
+ workflow.setCustName("cipher-name");
+ workflow.setIdNum("cipher-id");
+ workflow.setRepayMethod("分期");
+ workflow.setIsTradeConstruction("1");
+ workflow.setModelOutputId(23L);
+
+ ModelCorpOutputFields corpOutputFields = new ModelCorpOutputFields();
+ corpOutputFields.setCalculateRate("4.95");
+
+ when(loanPricingWorkflowMapper.selectOne(any())).thenReturn(workflow);
+ when(modelCorpOutputFieldsMapper.selectById(23L)).thenReturn(corpOutputFields);
+ when(sensitiveFieldCryptoService.decrypt("cipher-name")).thenReturn("上虞测试企业");
+ when(sensitiveFieldCryptoService.decrypt("cipher-id")).thenReturn("91330000123456789X");
+ when(loanPricingSensitiveDisplayService.maskCustName("上虞测试企业")).thenReturn("上虞***企业");
+ when(loanPricingSensitiveDisplayService.maskIdNum("91330000123456789X")).thenReturn("91*************89X");
+
+ LoanPricingWorkflowVO result = loanPricingWorkflowService.selectLoanPricingBySerialNum("C20260415001");
+
+ assertEquals("分期", result.getModelCorpOutputFields().getRepayMethod());
+ assertEquals("1", result.getModelCorpOutputFields().getIsTradeBuildEnt());
+ assertEquals("4.95", result.getLoanPricingWorkflow().getLoanRate());
+ }
}
diff --git a/ruoyi-ui/src/components/Breadcrumb/index.vue b/ruoyi-ui/src/components/Breadcrumb/index.vue
index 84f4831..87e6b9e 100644
--- a/ruoyi-ui/src/components/Breadcrumb/index.vue
+++ b/ruoyi-ui/src/components/Breadcrumb/index.vue
@@ -1,7 +1,7 @@
-
+
{{ item.meta.title }}
{{ item.meta.title }}
@@ -10,6 +10,8 @@