diff --git a/doc/api/loan-pricing-workflow-api.md b/doc/api/loan-pricing-workflow-api.md index 1cd38c7..aafc370 100644 --- a/doc/api/loan-pricing-workflow-api.md +++ b/doc/api/loan-pricing-workflow-api.md @@ -284,6 +284,7 @@ GET /loanPricing/workflow/20250119143025123 "idType": "身份证", "idNum": "330102199001011234", "baseLoanRate": "3.45", + "greyBlackCust": "1", "isFirstLoan": "true", "faithDay": "365", "custAge": "35", diff --git a/doc/implementation-report-2026-04-27-retail-grey-black-cust.md b/doc/implementation-report-2026-04-27-retail-grey-black-cust.md new file mode 100644 index 0000000..b023e9d --- /dev/null +++ b/doc/implementation-report-2026-04-27-retail-grey-black-cust.md @@ -0,0 +1,54 @@ +# 2026-04-27 个人模型输出灰黑名单客户字段实施记录 + +## 修改内容 + +- 后端个人模型输出实体 `ModelRetailOutputFields` 新增 `greyBlackCust` 字段,承接个人模型返回的 `0/1` 输出值。 +- 个人模型 mock 返回文件 `retail_output.json` 新增 `greyBlackCust: "1"`,用于本地模型调用链路验证。 +- `model_retail_output_fields` 表结构新增 `grey_black_cust` 字段,并补充增量迁移脚本 `sql/add_model_retail_grey_black_cust_20260427.sql`。 +- 前端模型输出组件在个人客户“基本信息”分组中展示“灰黑名单客户”,直接展示后端返回值 `0/1`。 +- 接口文档示例补充 `greyBlackCust` 返回字段。 + +## 涉及文件 + +- `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/entity/ModelRetailOutputFields.java` +- `ruoyi-loan-pricing/src/main/resources/data/retail_output.json` +- `ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/domain/entity/ModelRetailOutputFieldsTest.java` +- `ruoyi-ui/src/views/loanPricing/workflow/components/ModelOutputDisplay.vue` +- `ruoyi-ui/tests/retail-display-fields.test.js` +- `sql/model_retail.sql` +- `sql/loan_pricing_schema_20260328.sql` +- `sql/loan_pricing_prod_init_20260331.sql` +- `sql/add_model_retail_grey_black_cust_20260427.sql` +- `doc/api/loan-pricing-workflow-api.md` + +## 数据库变更 + +- 已在开发库 `loan-pricing.model_retail_output_fields` 执行新增列: + +```sql +ALTER TABLE model_retail_output_fields + ADD COLUMN grey_black_cust varchar(100) DEFAULT '' COMMENT '灰黑名单客户' AFTER base_loan_rate; +``` + +- 回查结果确认 `grey_black_cust` 字段存在。 + +## 验证记录 + +- `mvn -pl ruoyi-loan-pricing -Dtest=ModelRetailOutputFieldsTest,LoanPricingModelServiceTest -Dsurefire.failIfNoSpecifiedTests=false test` + - 通过,确认实体字段存在,个人/企业模型调用基础链路未回归。 +- `zsh -lic 'nvm use 14 >/dev/null && npm --prefix ruoyi-ui run test:retail-display-fields && npm --prefix ruoyi-ui run test:model-output-flat-display'` + - 通过,确认前端包含 `retailOutput.greyBlackCust` 且字段位于个人模型输出“基本信息”分组。 +- `zsh -lic 'nvm use 14 >/dev/null && npm --prefix ruoyi-ui run build:prod'` + - 通过,存在既有包体积 warning,无编译错误。 +- 后端真实接口验证: + - 重启后端后调用个人流程创建接口,业务流水号 `20260427153305173`。 + - 调用详情接口返回 `modelRetailOutputFields.greyBlackCust = 1`。 + - 数据库联表回查 `model_retail_output_fields.grey_black_cust = 1`。 +- browser-use 真实页面验证: + - 使用前端开发服务 `http://127.0.0.1:63311/` 打开真实流程详情页。 + - 页面 `模型输出 > 基本信息` 中可见“灰黑名单客户”,展示值为 `1`。 +- 测试结束后已停止本次启动的后端 `63310` 与前端 `63311` 进程,并回查端口不再监听。 + +## 备注 + +- 组合执行 `LoanPricingModelServicePersonalParamsTest` 时,当前本机 JDK 21 下 Mockito inline ByteBuddy 自附加失败;该失败与本次字段改动无关。已单独执行本次直接相关的非 Mockito 失败用例并通过。 diff --git a/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/entity/ModelRetailOutputFields.java b/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/entity/ModelRetailOutputFields.java index ee72e3a..09d069d 100644 --- a/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/entity/ModelRetailOutputFields.java +++ b/ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/entity/ModelRetailOutputFields.java @@ -41,6 +41,9 @@ public class ModelRetailOutputFields { // 基准利率 private String baseLoanRate; + // 灰黑名单客户 + private String greyBlackCust; + // 我行首贷客户 private String isFirstLoan; diff --git a/ruoyi-loan-pricing/src/main/resources/data/retail_output.json b/ruoyi-loan-pricing/src/main/resources/data/retail_output.json index 38777c1..68269ea 100644 --- a/ruoyi-loan-pricing/src/main/resources/data/retail_output.json +++ b/ruoyi-loan-pricing/src/main/resources/data/retail_output.json @@ -10,6 +10,7 @@ "idType": "身份证", "idNum": "330106199001011234", "baseLoanRate": "4.35", + "greyBlackCust": "1", "isFirstLoan": "是", "faithDay": "365", "custAge": "36", diff --git a/ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/domain/entity/ModelRetailOutputFieldsTest.java b/ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/domain/entity/ModelRetailOutputFieldsTest.java index bdd49ee..1802957 100644 --- a/ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/domain/entity/ModelRetailOutputFieldsTest.java +++ b/ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/domain/entity/ModelRetailOutputFieldsTest.java @@ -22,5 +22,6 @@ class ModelRetailOutputFieldsTest assertTrue(fieldNames.contains("smoothRange"), "缺少字段 smoothRange"); assertTrue(fieldNames.contains("finalCalculateRate"), "缺少字段 finalCalculateRate"); assertTrue(fieldNames.contains("referenceRate"), "缺少字段 referenceRate"); + assertTrue(fieldNames.contains("greyBlackCust"), "缺少字段 greyBlackCust"); } } diff --git a/ruoyi-ui/src/views/loanPricing/workflow/components/ModelOutputDisplay.vue b/ruoyi-ui/src/views/loanPricing/workflow/components/ModelOutputDisplay.vue index df73600..ef9c5cb 100644 --- a/ruoyi-ui/src/views/loanPricing/workflow/components/ModelOutputDisplay.vue +++ b/ruoyi-ui/src/views/loanPricing/workflow/components/ModelOutputDisplay.vue @@ -14,6 +14,7 @@ {{ retailOutput.idType || '-' }} {{ retailOutput.idNum || '-' }} {{ retailOutput.baseLoanRate || '-' }} % + {{ formatOutputValue(retailOutput.greyBlackCust) }} @@ -236,6 +237,10 @@ export default { if (value === 'consumer') return '消费贷款' if (value === 'business') return '经营贷款' return value || '-' + }, + formatOutputValue(value) { + if (value === 0) return '0' + return value || '-' } } } diff --git a/ruoyi-ui/tests/retail-display-fields.test.js b/ruoyi-ui/tests/retail-display-fields.test.js index 530cb85..22d9363 100644 --- a/ruoyi-ui/tests/retail-display-fields.test.js +++ b/ruoyi-ui/tests/retail-display-fields.test.js @@ -15,6 +15,7 @@ assert( ) const requiredRetailFields = [ + 'retailOutput.greyBlackCust', 'retailOutput.loanRateHistory', 'retailOutput.minRateProduct', 'retailOutput.smoothRange', @@ -26,4 +27,10 @@ requiredRetailFields.forEach((field) => { assert(modelOutput.includes(field), `模型输出缺少字段展示: ${field}`) }) +assert( + modelOutput.indexOf('label="灰黑名单客户"') > modelOutput.indexOf('

基本信息

') + && modelOutput.indexOf('label="灰黑名单客户"') < modelOutput.indexOf('

测算结果

'), + '灰黑名单客户未展示在个人模型输出基础信息中' +) + console.log('retail display fields assertions passed') diff --git a/sql/add_model_retail_grey_black_cust_20260427.sql b/sql/add_model_retail_grey_black_cust_20260427.sql new file mode 100644 index 0000000..23edd73 --- /dev/null +++ b/sql/add_model_retail_grey_black_cust_20260427.sql @@ -0,0 +1,2 @@ +ALTER TABLE `model_retail_output_fields` + ADD COLUMN `grey_black_cust` varchar(100) DEFAULT '' COMMENT '灰黑名单客户' AFTER `base_loan_rate`; diff --git a/sql/loan_pricing_prod_init_20260331.sql b/sql/loan_pricing_prod_init_20260331.sql index 3ca837b..647288a 100644 --- a/sql/loan_pricing_prod_init_20260331.sql +++ b/sql/loan_pricing_prod_init_20260331.sql @@ -873,6 +873,7 @@ CREATE TABLE `model_retail_output_fields` ( `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 '基准利率', + `grey_black_cust` 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 '客户年龄', diff --git a/sql/loan_pricing_schema_20260328.sql b/sql/loan_pricing_schema_20260328.sql index 8b33745..c4439ee 100644 --- a/sql/loan_pricing_schema_20260328.sql +++ b/sql/loan_pricing_schema_20260328.sql @@ -455,6 +455,7 @@ CREATE TABLE `model_retail_output_fields` ( `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 '基准利率', + `grey_black_cust` 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 '客户年龄', diff --git a/sql/model_retail.sql b/sql/model_retail.sql index e79a8ff..66ece17 100644 --- a/sql/model_retail.sql +++ b/sql/model_retail.sql @@ -20,6 +20,8 @@ CREATE TABLE IF NOT EXISTS model_retail_output_fields ( id_num VARCHAR(100) DEFAULT '' COMMENT '证件号码', -- 基准利率(百分比,如4.35) base_loan_rate VARCHAR(100) DEFAULT '' COMMENT '基准利率', + -- 灰黑名单客户(0/1) + grey_black_cust VARCHAR(100) DEFAULT '' COMMENT '灰黑名单客户', -- 我行首贷客户(是/否) is_first_loan VARCHAR(100) DEFAULT '' COMMENT '我行首贷客户', -- 用信天数