模型调用

This commit is contained in:
wkc
2026-01-21 15:58:39 +08:00
parent c4a05e1338
commit 0d061155ed
25 changed files with 1134 additions and 55 deletions

View File

@@ -14,7 +14,8 @@
"Bash(powershell -Command:*)",
"Bash(openspec archive add-loan-pricing-create:*)",
"Bash(git add:*)",
"Bash(cd:*)"
"Bash(cd:*)",
"mcp__zai-mcp-server__extract_text_from_screenshot"
],
"additionalDirectories": [
"d:\\利率定价\\loan-pricing-892\\loan-pricing-892-v2.0"

View File

@@ -11,6 +11,7 @@
## Java Code Style
- 在实体类中使用 `@Data` 注解保证代码的简洁
- 尽量使用 MyBatis Plus 进行 CRUD 操作(版本 3.5.10Spring Boot 3 适配版)
- 服务层中的使用@Resource注释,替代@Autowired
# 测试验证
- /login/test接口可以传入username和password获取token用于测试验证接口的功能。

View File

@@ -101,3 +101,5 @@ spring:
max-active: 8
# #连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms
model:
url: http://localhost:8080/rate/pricing/mock/invokeModel

View File

@@ -11,6 +11,8 @@ import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.Map;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
@@ -21,7 +23,10 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.utils.StringUtils;
import org.springframework.http.MediaType;
import org.springframework.http.*;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
/**
* 通用http发送方法
@@ -290,4 +295,79 @@ public class HttpUtils
return true;
}
}
/**
* 发送 POST 请求application/x-www-form-urlencoded 格式)
* @param url 请求地址
* @param params 表单参数
* @param headers 请求头(可为 null
* @param responseType 响应类型
* @param <T> 泛型返回值
* @return 响应结果
*/
public static <T> T doPostFormUrlEncoded(String url, Map<String, String> params, HttpHeaders headers, Class<T> responseType) {
// 构建表单参数
MultiValueMap<String, String> formParams = new LinkedMultiValueMap<>();
if (params != null && !params.isEmpty()) {
formParams.setAll(params);
}
// 构建请求头(指定 Content-Type
HttpHeaders requestHeaders = headers == null ? new HttpHeaders() : headers;
requestHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
requestHeaders.setAcceptCharset(Collections.singletonList(StandardCharsets.UTF_8));
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(formParams, requestHeaders);
RestTemplate restTemplate = new RestTemplate();
// 发送请求
try {
ResponseEntity<T> response = restTemplate.exchange(
url,
HttpMethod.POST,
requestEntity,
responseType
);
log.info("---------------------->POST(form-urlencoded) 请求成功URL{},响应结果:{}", url, response.getBody());
return response.getBody();
} catch (Exception e) {
throw new RuntimeException("POST(form-urlencoded) 请求失败URL" + url + ",异常信息:" + e.getMessage(), e);
}
}
// ========== 新增JSON 格式 POST 请求 ==========
/**
* 发送 POST 请求application/json 格式)
* @param url 请求地址
* @param requestBody 请求体Java 对象,自动序列化为 JSON
* @param headers 请求头(可为 null默认已设置 Content-Type: application/json
* @param responseType 响应类型
* @param <T> 响应泛型类型
* @param <R> 请求体类型
* @return 响应结果
*/
public static <T, R> T doPostJson(String url, R requestBody, HttpHeaders headers, Class<T> responseType) {
// 构建请求头,默认设置 JSON 格式
HttpHeaders requestHeaders = headers == null ? new HttpHeaders() : headers;
// 确保 Content-Type 为 JSON避免外部传入覆盖
if (!requestHeaders.containsKey(HttpHeaders.CONTENT_TYPE)) {
requestHeaders.setContentType(MediaType.APPLICATION_JSON_UTF8);
}
// 构建请求实体(请求体 + 请求头)
HttpEntity<R> requestEntity = new HttpEntity<>(requestBody, requestHeaders);
RestTemplate restTemplate = new RestTemplate();
// 发送 JSON POST 请求
try {
ResponseEntity<T> response = restTemplate.exchange(
url,
HttpMethod.POST,
requestEntity,
responseType
);
log.info("---------------------->POST(JSON) 请求成功URL{},响应结果:{}", url, response.getBody());
return response.getBody();
} catch (Exception e) {
throw new RuntimeException("POST(JSON) 请求失败URL" + url + ",异常信息:" + e.getMessage(), e);
}
}
}

View File

@@ -0,0 +1,33 @@
package com.ruoyi.framework.config.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.ruoyi.common.utils.SecurityUtils;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* 实体类自动配置创建日期和更新日期
*
* @author 600477
* @date 2023/6/6
*/
@Component
public class MyMetaHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createBy", SecurityUtils.getUsername(), metaObject);
this.setFieldValByName("createTime", new Date(), metaObject);
this.setFieldValByName("updateBy", SecurityUtils.getUsername(), metaObject);
this.setFieldValByName("updateTime", new Date(), metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateBy", SecurityUtils.getUsername(), metaObject);
this.setFieldValByName("updateTime", new Date(), metaObject);
}
}

View File

@@ -10,7 +10,8 @@ import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.page.TableSupport;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.loanpricing.domain.LoanPricingWorkflow;
import com.ruoyi.loanpricing.domain.entity.LoanPricingWorkflow;
import com.ruoyi.loanpricing.domain.vo.LoanPricingWorkflowVO;
import com.ruoyi.loanpricing.service.ILoanPricingWorkflowService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
@@ -41,10 +42,6 @@ public class LoanPricingWorkflowController extends BaseController
@PostMapping("/create")
public AjaxResult create(@Validated @RequestBody LoanPricingWorkflow loanPricingWorkflow)
{
// 设置创建者
loanPricingWorkflow.setCreateBy(SecurityUtils.getUsername());
loanPricingWorkflow.setUpdateBy(SecurityUtils.getUsername());
LoanPricingWorkflow result = loanPricingWorkflowService.createLoanPricing(loanPricingWorkflow);
return success(result);
}
@@ -76,7 +73,7 @@ public class LoanPricingWorkflowController extends BaseController
@Parameter(description = "业务方流水号")
@PathVariable("serialNum") String serialNum)
{
LoanPricingWorkflow workflow = loanPricingWorkflowService.selectLoanPricingBySerialNum(serialNum);
LoanPricingWorkflowVO workflow = loanPricingWorkflowService.selectLoanPricingBySerialNum(serialNum);
if (workflow == null)
{
return error("记录不存在");

View File

@@ -0,0 +1,55 @@
package com.ruoyi.loanpricing.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.loanpricing.domain.dto.ModelInvokeDTO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.bind.annotation.*;
import java.io.InputStream;
/**
* @Author 吴凯程
* @Date 2025/11/10
**/
@Tag(name = "测算测试接口")
@RestController
@RequestMapping("/rate/pricing/mock")
public class LoanRatePricingMockController extends BaseController {
@Anonymous
@Operation(summary = "调用模型获取测算利率")
@PostMapping("/invokeModel")
public AjaxResult invokeModel( ModelInvokeDTO modelInvokeDTO) {
ObjectNode jsonNodes;
if (modelInvokeDTO.getCustType().equals("个人")) {
jsonNodes = loadJsonFromResource("data/retail_output.json");
} else {
jsonNodes = loadJsonFromResource("data/corp_output.json");
}
return new AjaxResult(10000, "success", jsonNodes);
}
private ObjectNode loadJsonFromResource(String resourcePath){
ClassPathResource classPathResource = new ClassPathResource(resourcePath);
try (InputStream inputStream = classPathResource.getInputStream();){
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(inputStream, ObjectNode.class);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,153 @@
package com.ruoyi.loanpricing.domain.dto;
import lombok.Data;
/**
* @Author 吴凯程
* @Date 2025/12/23
**/
@Data
public class ModelInvokeDTO {
/**
* 业务方流水号(必填)
* 可使用时间戳,或自定义随机生成
*/
private String serialNum;
/**
* 机构编码(必填)
* 固定值931000
*/
private String orgCode;
/**
* 运行模式(必填)
* 固定值1:同步
*/
private String runType = "1";
/**
* 客户内码(必填)
*/
private String custIsn;
/**
* 客户类型(必填)
* 可选值:个人/企业
*/
private String custType;
/**
* 担保方式(必填)
* 可选值:信用,保证,抵押,质押
*/
private String guarType;
/**
* 中间业务_个人_快捷支付非必填
* 可选值true/false
*/
private String midPerQuickPay;
/**
* 中间业务_个人_电费代扣非必填
* 可选值true/false
*/
private String midPerEleDdc;
/**
* 中间业务_企业_电费代扣非必填
* 可选值true/false
*/
private String midEntEleDdc;
/**
* 中间业务_企业_水费代扣非必填
* 可选值true/false
*/
private String midEntWaterDdc;
/**
* 申请金额(必填)
* 单位:元
*/
private String applyAmt;
/**
* 净身企业(非必填)
* 可选值true/false
*/
private String isCleanEnt;
/**
* 开立基本结算账户(非必填)
* 可选值true/false
*/
private String hasSettleAcct;
/**
* 制造业企业(非必填)
* 可选值true/false
*/
private String isManufacturing;
/**
* 省农担担保贷款(非必填)
* 可选值true/false
*/
private String isAgriGuar;
/**
* 是否纳税信用等级A级非必填
* 可选值true/false
*/
private String isTaxA;
/**
* 是否县级及以上农业龙头企业(非必填)
* 可选值true/false
*/
private String isAgriLeading;
private String isInclusiveFinance;
/**
* 贷款用途(非必填)
* 可选值consumer/business
*/
private String loanPurpose;
/**
* 是否有经营佐证(非必填)
* 可选值true/false
*/
private String bizProof;
/**
* 抵质押类型(非必填)
* 可选值:抵押/质押
*/
private String collType;
/**
* 抵质押物是否三方所有(非必填)
* 可选值true/false
*/
private String collThirdParty;
// /**
// * 贷款利率(必填)
// */
// private String loanRate;
/**
* 客户名称(非必填)
*/
private String custName;
/**
* 证件类型(非必填)
*/
private String idType;
}

View File

@@ -1,8 +1,6 @@
package com.ruoyi.loanpricing.domain;
package com.ruoyi.loanpricing.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
@@ -27,6 +25,9 @@ public class LoanPricingWorkflow implements Serializable
@TableId(type = IdType.AUTO)
private Long id;
/** 模型输出ID */
private Long modelOutputId;
/** 业务方流水号 */
private String serialNum;
@@ -108,16 +109,20 @@ public class LoanPricingWorkflow implements Serializable
private String isInclusiveFinance;
/** 创建者 */
@TableField(fill = FieldFill.INSERT)
private String createBy;
/** 创建时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField(fill = FieldFill.INSERT)
private Date createTime;
/** 更新者 */
@TableField(fill = FieldFill.INSERT_UPDATE)
private String updateBy;
/** 更新时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
}

View File

@@ -0,0 +1,125 @@
package com.ruoyi.loanpricing.domain.entity;
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 lombok.Data;
import java.util.Date;
/**
* 贷款定价模型输入参数对象
*
* @author ruoyi
* @date 2025-01-21
*/
@Data
public class ModelCorpOutputFields {
@TableId(type = IdType.AUTO)
private Long id;
// 客户内码
private String custIsn;
// 客户类型
private String custType;
// 担保方式
private String guarType;
// 客户名称
private String custName;
// 证件类型
private String idType;
// 证件号码
private String idNum;
// 基准利率
private String baseLoanRate;
// 我行首贷客户
private String isFirstLoan;
// 用信天数
private String faithDay;
// BP_首贷
private String bpFirstLoan;
// BP_贷龄
private String bpAgeLoan;
// TOTAL_BP_忠诚度
private String totalBpLoyalty;
// 存款年日均
private String balanceAvg;
// 贷款年日均
private String loanAvg;
// 派生率
private String derivationRate;
// TOTAL_BP_贡献度
private String totalBpContribution;
// 中间业务_企业_企业互联
private String midEntConnect;
// 中间业务_企业_有效价值客户
private String midEntEffect;
// 中间业务_企业_国际业务
private String midEntInter;
// 中间业务_企业_承兑
private String midEntAccept;
// 中间业务_企业_贴现
private String midEntDiscount;
// 中间业务_企业_电费代扣
private String midEntEleDdc;
// 中间业务_企业_水费代扣
private String midEntWaterDdc;
// 中间业务_企业_税务代扣
private String midEntTax;
// BP_中间业务
private String bpMid;
// 代发工资户数
private String payroll;
// 存量贷款余额
private String invLoanAmount;
// BP_代发工资
private String bpPayroll;
// 净身企业
private String isCleanEnt;
// 开立基本结算账户
private String hasSettleAcct;
// 省农担担保贷款
private String isAgriGuar;
// 绿色贷款
private String isGreenLoan;
// 科技型企业
private String isTechEnt;
// BP_企业客户类别
private String bpEntType;
// TOTAL_BP_关联度
private String totoalBpRelevance;
// 贷款期限
private String loanTerm;
// BP_贷款期限
private String bpLoanTerm;
// 申请金额
private String applyAmt;
// BP_贷款额度
private String bpLoanAmount;
// 抵质押类型
private String collType;
// 抵质押物是否三方所有
private String collThirdParty;
// BP_抵押物
private String bpCollateral;
// 灰名单客户
private String greyCust;
// 本金逾期
private String prinOverdue;
// 利息逾期
private String interestOverdue;
// 信用卡逾期
private String cardOverdue;
// BP_灰名单与逾期
private String bpGreyOverdue;
// TOTAL_BP_风险度
private String totoalBpRisk;
// 浮动BP
private String totalBp;
// 测算利率
private String calculateRate;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
}

View File

@@ -0,0 +1,175 @@
package com.ruoyi.loanpricing.domain.entity;
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 lombok.Data;
import java.util.Date;
/**
* 贷款定价模型输入参数对象
*
* @author ruoyi
* @date 2025-01-21
*/
@Data
public class ModelRetailOutputFields {
@TableId(type = IdType.AUTO)
private Long id;
// 客户内码
private String custIsn;
// 客户类型
private String custType;
// 担保方式
private String guarType;
// 客户名称
private String custName;
// 证件类型
private String idType;
// 证件号码
private String idNum;
// 基准利率
private String baseLoanRate;
// 我行首贷客户
private String isFirstLoan;
// 用信天数
private String faithDay;
// 客户年龄
private String custAge;
// BP_首贷
private String bpFirstLoan;
// BP_贷龄
private String bpAgeLoan;
// BP_年龄
private String bpAge;
// TOTAL_BP_忠诚度
private String totalBpLoyalty;
// 存款年日均
private String balanceAvg;
// 贷款年日均
private String loanAvg;
// 派生率
private String derivationRate;
// TOTAL_BP_贡献度
private String totalBpContribution;
// 中间业务_个人_信用卡
private String midPerCard;
// 中间业务_个人_一码通
private String midPerPass;
// 中间业务_个人_丰收互联
private String midPerHarvest;
// 中间业务_个人_有效客户
private String midPerEffect;
// 中间业务_个人_快捷支付
private String midPerQuickPay;
// 中间业务_个人_电费代扣
private String midPerEleDdc;
// 中间业务_个人_水费代扣
private String midPerWaterDdc;
// 中间业务_个人_华数费代扣
private String midPerHuashuDdc;
// 中间业务_个人_煤气费代扣
private String MidPerGasDdc;
// 中间业务_个人_市民卡
private String midPerCitizencard;
// 中间业务_个人_理财业务
private String midPerFinMan;
// 中间业务_个人_etc
private String midPerEtc;
// BP_中间业务
private String bpMid;
// TOTAL_BP_关联度注意原字段名拼写错误totoalBpRelevance已保留原拼写
private String totoalBpRelevance;
// 申请金额
private String applyAmt;
// BP_贷款额度
private String bpLoanAmount;
// 贷款用途
private String loanPurpose;
// 是否有经营佐证
private String bizProof;
// BP_贷款用途
private String bpLoanUse;
// 循环功能
private String loanLoop;
// BP_循环功能
private String bpLoanLoop;
// 抵质押类型
private String collType;
// 抵质押物是否三方所有
private String collThirdParty;
// BP_抵押物
private String bpCollateral;
// 灰名单客户
private String greyCust;
// 本金逾期
private String prinOverdue;
// 利息逾期
private String interestOverdue;
// 信用卡逾期
private String cardOverdue;
// BP_灰名单与逾期
private String bpGreyOverdue;
// TOTAL_BP_风险度注意原字段名拼写错误totoalBpRisk已保留原拼写
private String totoalBpRisk;
// 浮动BP
private String totalBp;
// 测算利率
private String calculateRate;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
}

View File

@@ -0,0 +1,21 @@
package com.ruoyi.loanpricing.domain.vo;
import com.ruoyi.loanpricing.domain.entity.LoanPricingWorkflow;
import com.ruoyi.loanpricing.domain.entity.ModelCorpOutputFields;
import com.ruoyi.loanpricing.domain.entity.ModelRetailOutputFields;
import lombok.Data;
/**
* @Author: wkc
* @CreateTime: 2026-01-21
*/
@Data
public class LoanPricingWorkflowVO {
private LoanPricingWorkflow loanPricingWorkflow;
private ModelRetailOutputFields modelRetailOutputFields;
private ModelCorpOutputFields modelCorpOutputFields;
}

View File

@@ -1,10 +1,7 @@
package com.ruoyi.loanpricing.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.loanpricing.domain.LoanPricingWorkflow;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import com.ruoyi.loanpricing.domain.entity.LoanPricingWorkflow;
/**
* 利率定价流程Mapper接口

View File

@@ -0,0 +1,15 @@
package com.ruoyi.loanpricing.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.loanpricing.domain.entity.ModelCorpOutputFields;
/**
* 对公贷款定价模型输出字段Mapper接口
*
* @author ruoyi
* @date 2025-01-21
*/
public interface ModelCorpOutputFieldsMapper extends BaseMapper<ModelCorpOutputFields>
{
}

View File

@@ -0,0 +1,15 @@
package com.ruoyi.loanpricing.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.loanpricing.domain.entity.ModelRetailOutputFields;
/**
* 零售贷款定价模型输出字段Mapper接口
*
* @author ruoyi
* @date 2025-01-21
*/
public interface ModelRetailOutputFieldsMapper extends BaseMapper<ModelRetailOutputFields>
{
}

View File

@@ -2,7 +2,8 @@ package com.ruoyi.loanpricing.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.loanpricing.domain.LoanPricingWorkflow;
import com.ruoyi.loanpricing.domain.entity.LoanPricingWorkflow;
import com.ruoyi.loanpricing.domain.vo.LoanPricingWorkflowVO;
import java.util.List;
@@ -45,5 +46,5 @@ public interface ILoanPricingWorkflowService
* @param serialNum 业务方流水号
* @return 利率定价流程
*/
public LoanPricingWorkflow selectLoanPricingBySerialNum(String serialNum);
public LoanPricingWorkflowVO selectLoanPricingBySerialNum(String serialNum);
}

View File

@@ -0,0 +1,69 @@
package com.ruoyi.loanpricing.service;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.loanpricing.domain.dto.ModelInvokeDTO;
import com.ruoyi.loanpricing.domain.entity.LoanPricingWorkflow;
import com.ruoyi.loanpricing.domain.entity.ModelCorpOutputFields;
import com.ruoyi.loanpricing.domain.entity.ModelRetailOutputFields;
import com.ruoyi.loanpricing.mapper.LoanPricingWorkflowMapper;
import com.ruoyi.loanpricing.mapper.ModelCorpOutputFieldsMapper;
import com.ruoyi.loanpricing.mapper.ModelRetailOutputFieldsMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Service;
import java.util.Objects;
/**
* @Author: wkc
* @CreateTime: 2026-01-21
*/
@Service
@Slf4j
@EnableAsync
public class LoanPricingModelService {
@Resource
private ModelService modelService;
@Resource
private LoanPricingWorkflowMapper loanPricingWorkflowMapper;
@Resource
private ModelRetailOutputFieldsMapper modelRetailOutputFieldsMapper;
@Resource
private ModelCorpOutputFieldsMapper modelCorpOutputFieldsMapper;
public void invokeModelAsync(Long workflowId) {
LoanPricingWorkflow loanPricingWorkflow = loanPricingWorkflowMapper.selectById(workflowId);
if (Objects.isNull(loanPricingWorkflow)){
log.error("未找到对应的流程信息,未调用模型服务");
return;
}
ModelInvokeDTO modelInvokeDTO = new ModelInvokeDTO();
BeanUtils.copyProperties(loanPricingWorkflow, modelInvokeDTO);
JSONObject response = modelService.invokeModel(modelInvokeDTO);
if (loanPricingWorkflow.getCustType().equals("个人")){
// 个人模型
ModelRetailOutputFields modelRetailOutputFields = JSON.parseObject(response.toJSONString(), ModelRetailOutputFields.class);
modelRetailOutputFieldsMapper.insert(modelRetailOutputFields);
log.info("个人模型调用成功");
loanPricingWorkflow.setModelOutputId(modelRetailOutputFields.getId());
loanPricingWorkflowMapper.updateById(loanPricingWorkflow);
log.info("更新流程信息成功");
}else if (loanPricingWorkflow.getCustType().equals("企业")){
// 企业模型
ModelCorpOutputFields modelCorpOutputFields = JSON.parseObject(response.toJSONString(), ModelCorpOutputFields.class);
modelCorpOutputFieldsMapper.insert(modelCorpOutputFields);
log.info("企业模型调用成功");
loanPricingWorkflow.setModelOutputId(modelCorpOutputFields.getId());
loanPricingWorkflowMapper.updateById(loanPricingWorkflow);
log.info("更新流程信息成功");
}
}
}

View File

@@ -7,14 +7,15 @@ import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.loanratepricing.domain.RatePricingProperties;
import com.ruoyi.loanratepricing.domain.dto.ModelInvokeDTO;
import com.ruoyi.loanratepricing.domain.entity.ModelOutputFields;
import com.ruoyi.loanpricing.domain.dto.ModelInvokeDTO;
import com.ruoyi.loanpricing.domain.entity.LoanPricingWorkflow;
import org.springframework.beans.factory.annotation.Value;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -24,28 +25,28 @@ import java.util.Objects;
**/
@Service
@Slf4j
@EnableAsync
public class ModelService {
@Resource
private RatePricingProperties ratePricingProperties;
@Value("${model.url}")
private String modelUrl;
@Resource
private RedisCache redisCache;
public ModelOutputFields invokeModel(ModelInvokeDTO modelInvokeDTO) {
public JSONObject invokeModel(ModelInvokeDTO modelInvokeDTO) {
Map<String, String> requestBody = entityToMap(modelInvokeDTO);
JSONObject response = HttpUtils.doPostFormUrlEncoded(ratePricingProperties.getModelUrl(), requestBody, null, JSONObject.class);
JSONObject response = HttpUtils.doPostFormUrlEncoded(modelUrl, requestBody, null, JSONObject.class);
log.info("------------------->调用模型返回结果:" + JSON.toJSONString(response));
if(Objects.nonNull(response) && response.containsKey("code") && response.getInteger("code") == 10000){
JSONObject mappingOutputFields = response.getJSONObject("data").getJSONObject("mappingOutputFields");
return JSON.parseObject(mappingOutputFields.toJSONString(), ModelOutputFields.class);
// return JSON.parseObject(mappingOutputFields.toJSONString(), ModelOutputFields.class);
return mappingOutputFields;
}else{
log.error("------------------->调用模型失败,失败原因为:" + response.getString("message"));
throw new ServiceException("调用模型失败");
}
}
/**
* 使用FastJSON将实体类转换为Map<String, String>
* @param obj 待转换的实体类对象
@@ -60,16 +61,6 @@ public class ModelService {
return JSON.parseObject(jsonStr, new TypeReference<Map<String, String>>() {});
}
private void replaceIndicatorToVariableName(JSONObject jsonObject) {
List<SysDictData> variableNameList = redisCache.getCacheObject("sys_dict:model_indicator_metric");
variableNameList.forEach(sysDictData -> {
if (jsonObject.containsKey(sysDictData.getDictLabel())) {
jsonObject.put(sysDictData.getDictValue(), jsonObject.get(sysDictData.getDictLabel()));
jsonObject.remove(sysDictData.getDictLabel());
}
});
}

View File

@@ -3,16 +3,24 @@ package com.ruoyi.loanpricing.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.loanpricing.domain.LoanPricingWorkflow;
import com.ruoyi.loanpricing.domain.entity.LoanPricingWorkflow;
import com.ruoyi.loanpricing.domain.entity.ModelCorpOutputFields;
import com.ruoyi.loanpricing.domain.entity.ModelRetailOutputFields;
import com.ruoyi.loanpricing.domain.vo.LoanPricingWorkflowVO;
import com.ruoyi.loanpricing.mapper.LoanPricingWorkflowMapper;
import com.ruoyi.loanpricing.mapper.ModelCorpOutputFieldsMapper;
import com.ruoyi.loanpricing.mapper.ModelRetailOutputFieldsMapper;
import com.ruoyi.loanpricing.service.ILoanPricingWorkflowService;
import org.springframework.beans.factory.annotation.Autowired;
import com.ruoyi.loanpricing.service.LoanPricingModelService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Objects;
/**
* 利率定价流程Service业务层处理
@@ -23,9 +31,19 @@ import java.util.List;
@Service
public class LoanPricingWorkflowServiceImpl implements ILoanPricingWorkflowService
{
@Autowired
@Resource
private LoanPricingWorkflowMapper loanPricingWorkflowMapper;
@Resource
private LoanPricingModelService loanPricingModelService;
@Resource
private ModelRetailOutputFieldsMapper modelRetailOutputFieldsMapper;
@Resource
private ModelCorpOutputFieldsMapper modelCorpOutputFieldsMapper;
/**
* 发起利率定价流程
*
@@ -33,6 +51,7 @@ public class LoanPricingWorkflowServiceImpl implements ILoanPricingWorkflowServi
* @return 结果
*/
@Override
@Transactional(rollbackFor = Exception.class)
public LoanPricingWorkflow createLoanPricing(LoanPricingWorkflow loanPricingWorkflow)
{
// 自动生成业务方流水号(时间戳)
@@ -43,19 +62,16 @@ public class LoanPricingWorkflowServiceImpl implements ILoanPricingWorkflowServi
// 设置默认值
if (!StringUtils.hasText(loanPricingWorkflow.getOrgCode()))
{
loanPricingWorkflow.setOrgCode("931000");
loanPricingWorkflow.setOrgCode("892000");
}
if (!StringUtils.hasText(loanPricingWorkflow.getRunType()))
{
loanPricingWorkflow.setRunType("1");
}
// 设置创建时间和更新时间
Date now = new Date();
loanPricingWorkflow.setCreateTime(now);
loanPricingWorkflow.setUpdateTime(now);
loanPricingWorkflowMapper.insert(loanPricingWorkflow);
loanPricingModelService.invokeModelAsync(loanPricingWorkflow.getId());
return loanPricingWorkflow;
}
@@ -97,11 +113,28 @@ public class LoanPricingWorkflowServiceImpl implements ILoanPricingWorkflowServi
* @return 利率定价流程
*/
@Override
public LoanPricingWorkflow selectLoanPricingBySerialNum(String serialNum)
public LoanPricingWorkflowVO selectLoanPricingBySerialNum(String serialNum)
{
LoanPricingWorkflowVO loanPricingWorkflowVO = new LoanPricingWorkflowVO();
LambdaQueryWrapper<LoanPricingWorkflow> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(LoanPricingWorkflow::getSerialNum, serialNum);
return loanPricingWorkflowMapper.selectOne(wrapper);
LoanPricingWorkflow loanPricingWorkflow = loanPricingWorkflowMapper.selectOne(wrapper);
loanPricingWorkflowVO.setLoanPricingWorkflow(loanPricingWorkflow);
if (Objects.nonNull(loanPricingWorkflow.getModelOutputId())){
if (loanPricingWorkflow.getCustType().equals("个人")){
ModelRetailOutputFields modelRetailOutputFields = modelRetailOutputFieldsMapper.selectById(loanPricingWorkflow.getModelOutputId());
loanPricingWorkflowVO.setModelRetailOutputFields(modelRetailOutputFields);
}
if (loanPricingWorkflow.getCustType().equals("企业")){
ModelCorpOutputFields modelCorpOutputFields = modelCorpOutputFieldsMapper.selectById(loanPricingWorkflow.getModelOutputId());
loanPricingWorkflowVO.setModelCorpOutputFields(modelCorpOutputFields);
}
}
return loanPricingWorkflowVO;
}
/**

View File

@@ -0,0 +1,68 @@
{
"traceId": "350626558347246735E7F4722CUZRWOMNRR53O0",
"cost": 2267,
"tokenId": "17364055486305E7F4722M8IPFWNL8TOBEB",
"mappingOutputFields": {
"custIsn": "CUST20260121001",
"custType": "企业客户",
"guarType": "抵押担保",
"custName": "北京智联科技有限公司",
"idType": "营业执照",
"idNum": "91110108MA00XXXXXX",
"baseLoanRate": "3.45",
"isFirstLoan": "N",
"faithDay": "730",
"bpFirstLoan": "0",
"bpAgeLoan": "5.2",
"totalBpLoyalty": "8.5",
"balanceAvg": "5000000.00",
"loanAvg": "3000000.00",
"derivationRate": "1.8",
"totalBpContribution": "12.3",
"midEntConnect": "100000.00",
"midEntEffect": "50000.00",
"midEntInter": "80000.00",
"midEntAccept": "200000.00",
"midEntDiscount": "150000.00",
"midEntEleDdc": "30000.00",
"midEntWaterDdc": "10000.00",
"midEntTax": "40000.00",
"bpMid": "6.8",
"payroll": "200",
"invLoanAmount": "2500000.00",
"bpPayroll": "4.1",
"isCleanEnt": "Y",
"hasSettleAcct": "Y",
"isAgriGuar": "N",
"isGreenLoan": "Y",
"isTechEnt": "Y",
"bpEntType": "7.5",
"totoalBpRelevance": "9.2",
"loanTerm": "36",
"bpLoanTerm": "3.3",
"applyAmt": "5000000.00",
"bpLoanAmount": "5.8",
"collType": "房产抵押",
"collThirdParty": "N",
"bpCollateral": "4.5",
"greyCust": "N",
"prinOverdue": "N",
"interestOverdue": "N",
"cardOverdue": "N",
"bpGreyOverdue": "0",
"totoalBpRisk": "1.2",
"totalBp": "48.2",
"calculateRate": "3.932"
},
"extensionMap": {},
"reasonMessage": "Running successfully",
"bizTime": 1736405548630,
"outputFields": {},
"workflowCode": "TBKH",
"orgCode": "802000",
"bizId": "2025010914345",
"reasonCode": 200,
"workflowVersion": 14,
"callTime": 1736405548630,
"status": 1
}

View File

@@ -0,0 +1,68 @@
{
"traceId": "350626558347246735E7F4722CUZRWOMNRR53O0",
"cost": 2267,
"tokenId": "17364055486305E7F4722M8IPFWNL8TOBEB",
"mappingOutputFields": {
"custIsn": "CUST20260121001",
"custType": "个人",
"guarType": "信用担保",
"custName": "张三",
"idType": "身份证",
"idNum": "330106199001011234",
"baseLoanRate": "4.35",
"isFirstLoan": "是",
"faithDay": "365",
"custAge": "36",
"bpFirstLoan": "50",
"bpAgeLoan": "30",
"bpAge": "20",
"totalBpLoyalty": "95",
"balanceAvg": "50000.00",
"loanAvg": "100000.00",
"derivationRate": "1.2",
"totalBpContribution": "88",
"midPerCard": "1000.50",
"midPerPass": "500.00",
"midPerHarvest": "800.20",
"midPerEffect": "是",
"midPerQuickPay": "300.00",
"midPerEleDdc": "150.00",
"midPerWaterDdc": "80.00",
"midPerHuashuDdc": "120.00",
"MidPerGasDdc": "90.00",
"midPerCitizencard": "200.00",
"midPerFinMan": "5000.00",
"midPerEtc": "180.00",
"bpMid": "45",
"totoalBpRelevance": "90",
"applyAmt": "200000.00",
"bpLoanAmount": "60",
"loanPurpose": "个人消费",
"bizProof": "有",
"bpLoanUse": "55",
"loanLoop": "支持",
"bpLoanLoop": "40",
"collType": "无抵质押",
"collThirdParty": "否",
"bpCollateral": "0",
"greyCust": "否",
"prinOverdue": "否",
"interestOverdue": "否",
"cardOverdue": "否",
"bpGreyOverdue": "98",
"totoalBpRisk": "95",
"totalBp": "350",
"calculateRate": "6.15"
},
"extensionMap": {},
"reasonMessage": "Running successfully",
"bizTime": 1736405548630,
"outputFields": {},
"workflowCode": "TBKH",
"orgCode": "802000",
"bizId": "2025010914345",
"reasonCode": 200,
"workflowVersion": 14,
"callTime": 1736405548630,
"status": 1
}

View File

@@ -226,7 +226,7 @@ export default {
/** 表单重置 */
reset() {
this.form = {
orgCode: '931000',
orgCode: '',
runType: '1',
custIsn: undefined,
custName: undefined,

View File

@@ -3,7 +3,8 @@ DROP TABLE IF EXISTS `loan_pricing_workflow`;
CREATE TABLE `loan_pricing_workflow` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`serial_num` varchar(50) NOT NULL COMMENT '业务方流水号',
`org_code` varchar(20) NOT NULL DEFAULT '931000' COMMENT '机构编码',
`model_output_id` bigint(20) 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 '客户类型: 个人/企业',

59
sql/model_corp.sql Normal file
View File

@@ -0,0 +1,59 @@
/*
* 客户贷款利率测算表
*/
DROP TABLE IF EXISTS model_corp_output_fields;
CREATE TABLE `model_corp_output_fields` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增主键ID',
`cust_isn` VARCHAR(100) COMMENT '客户内码',
`cust_type` VARCHAR(100) COMMENT '客户类型',
`guar_type` VARCHAR(100) COMMENT '担保方式',
`cust_name` VARCHAR(100) COMMENT '客户名称',
`id_type` VARCHAR(100) COMMENT '证件类型',
`id_num` VARCHAR(100) COMMENT '证件号码',
`base_loan_rate` VARCHAR(100) COMMENT '基准利率',
`is_first_loan` VARCHAR(100) COMMENT '我行首贷客户',
`faith_day` VARCHAR(100) COMMENT '用信天数',
`bp_first_loan` VARCHAR(100) COMMENT 'BP_首贷',
`bp_age_loan` VARCHAR(100) COMMENT 'BP_贷龄',
`total_bp_loyalty` VARCHAR(100) COMMENT 'TOTAL_BP_忠诚度',
`balance_avg` VARCHAR(100) COMMENT '存款年日均',
`loan_avg` VARCHAR(100) COMMENT '贷款年日均',
`derivation_rate` VARCHAR(100) COMMENT '派生率',
`total_bp_contribution` VARCHAR(100) COMMENT 'TOTAL_BP_贡献度',
`mid_ent_connect` VARCHAR(100) COMMENT '中间业务_企业_企业互联',
`mid_ent_effect` VARCHAR(100) COMMENT '中间业务_企业_有效价值客户',
`mid_ent_inter` VARCHAR(100) COMMENT '中间业务_企业_国际业务',
`mid_ent_accept` VARCHAR(100) COMMENT '中间业务_企业_承兑',
`mid_ent_discount` VARCHAR(100) COMMENT '中间业务_企业_贴现',
`mid_ent_ele_ddc` VARCHAR(100) COMMENT '中间业务_企业_电费代扣',
`mid_ent_water_ddc` VARCHAR(100) COMMENT '中间业务_企业_水费代扣',
`mid_ent_tax` VARCHAR(100) COMMENT '中间业务_企业_税务代扣',
`bp_mid` VARCHAR(100) COMMENT 'BP_中间业务',
`payroll` VARCHAR(100) COMMENT '代发工资户数',
`inv_loan_amount` VARCHAR(100) COMMENT '存量贷款余额',
`bp_payroll` VARCHAR(100) COMMENT 'BP_代发工资',
`is_clean_ent` VARCHAR(100) COMMENT '净身企业',
`has_settle_acct` VARCHAR(100) COMMENT '开立基本结算账户',
`is_agri_guar` VARCHAR(100) COMMENT '省农担担保贷款',
`is_green_loan` VARCHAR(100) COMMENT '绿色贷款',
`is_tech_ent` VARCHAR(100) COMMENT '科技型企业',
`bp_ent_type` VARCHAR(100) COMMENT 'BP_企业客户类别',
`totoal_bp_relevance` VARCHAR(100) COMMENT 'TOTAL_BP_关联度',
`loan_term` VARCHAR(100) COMMENT '贷款期限',
`bp_loan_term` VARCHAR(100) COMMENT 'BP_贷款期限',
`apply_amt` VARCHAR(100) COMMENT '申请金额',
`bp_loan_amount` VARCHAR(100) COMMENT 'BP_贷款额度',
`coll_type` VARCHAR(100) COMMENT '抵质押类型',
`coll_third_party` VARCHAR(100) COMMENT '抵质押物是否三方所有',
`bp_collateral` VARCHAR(100) COMMENT 'BP_抵押物',
`grey_cust` VARCHAR(100) COMMENT '灰名单客户',
`prin_overdue` VARCHAR(100) COMMENT '本金逾期',
`interest_overdue` VARCHAR(100) COMMENT '利息逾期',
`card_overdue` VARCHAR(100) COMMENT '信用卡逾期',
`bp_grey_overdue` VARCHAR(100) COMMENT 'BP_灰名单与逾期',
`totoal_bp_risk` VARCHAR(100) COMMENT 'TOTAL_BP_风险度',
`total_bp` VARCHAR(100) COMMENT '浮动BP',
`calculate_rate` VARCHAR(100) COMMENT '测算利率',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='客户贷款利率测算表';

114
sql/model_retail.sql Normal file
View File

@@ -0,0 +1,114 @@
/*
* 零售模型输出字段表
* 存储客户基本信息、BP评分、资产信息、风险信息等贷款测算相关数据
*/
DROP TABLE IF EXISTS model_retail_output_fields;
CREATE TABLE IF NOT EXISTS model_retail_output_fields (
-- 主键ID自增用于表的唯一标识
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',
-- 客户内码(业务唯一标识)
cust_isn VARCHAR(100) NOT NULL COMMENT '客户内码',
-- 客户类型(如:个人/企业)
cust_type VARCHAR(100) DEFAULT '' COMMENT '客户类型',
-- 担保方式(如:信用担保/抵押担保)
guar_type VARCHAR(100) DEFAULT '' COMMENT '担保方式',
-- 客户名称
cust_name VARCHAR(100) DEFAULT '' COMMENT '客户名称',
-- 证件类型(如:身份证/营业执照)
id_type VARCHAR(100) DEFAULT '' COMMENT '证件类型',
-- 证件号码(脱敏存储)
id_num VARCHAR(100) DEFAULT '' COMMENT '证件号码',
-- 基准利率百分比如4.35
base_loan_rate VARCHAR(100) DEFAULT '' COMMENT '基准利率',
-- 我行首贷客户(是/否)
is_first_loan VARCHAR(100) DEFAULT '' COMMENT '我行首贷客户',
-- 用信天数
faith_day VARCHAR(100) DEFAULT '' COMMENT '用信天数',
-- 客户年龄
cust_age VARCHAR(100) DEFAULT '' COMMENT '客户年龄',
-- BP_首贷
bp_first_loan VARCHAR(100) DEFAULT '' COMMENT 'BP_首贷',
-- BP_贷龄
bp_age_loan VARCHAR(100) DEFAULT '' COMMENT 'BP_贷龄',
-- BP_年龄
bp_age VARCHAR(100) DEFAULT '' COMMENT 'BP_年龄',
-- TOTAL_BP_忠诚度
total_bp_loyalty VARCHAR(100) DEFAULT '' COMMENT 'TOTAL_BP_忠诚度',
-- 存款年日均(元)
balance_avg VARCHAR(100) DEFAULT '' COMMENT '存款年日均',
-- 贷款年日均(元)
loan_avg VARCHAR(100) DEFAULT '' COMMENT '贷款年日均',
-- 派生率
derivation_rate VARCHAR(100) DEFAULT '' COMMENT '派生率',
-- TOTAL_BP_贡献度
total_bp_contribution VARCHAR(100) DEFAULT '' COMMENT 'TOTAL_BP_贡献度',
-- 中间业务_个人_信用卡
mid_per_card VARCHAR(100) DEFAULT '' COMMENT '中间业务_个人_信用卡',
-- 中间业务_个人_一码通
mid_per_pass VARCHAR(100) DEFAULT '' COMMENT '中间业务_个人_一码通',
-- 中间业务_个人_丰收互联
mid_per_harvest VARCHAR(100) DEFAULT '' COMMENT '中间业务_个人_丰收互联',
-- 中间业务_个人_有效客户是/否)
mid_per_effect VARCHAR(100) DEFAULT '' COMMENT '中间业务_个人_有效客户',
-- 中间业务_个人_快捷支付
mid_per_quick_pay VARCHAR(100) DEFAULT '' COMMENT '中间业务_个人_快捷支付',
-- 中间业务_个人_电费代扣
mid_per_ele_ddc VARCHAR(100) DEFAULT '' COMMENT '中间业务_个人_电费代扣',
-- 中间业务_个人_水费代扣
mid_per_water_ddc VARCHAR(100) DEFAULT '' COMMENT '中间业务_个人_水费代扣',
-- 中间业务_个人_华数费代扣
mid_per_huashu_ddc VARCHAR(100) DEFAULT '' COMMENT '中间业务_个人_华数费代扣',
-- 中间业务_个人_煤气费代扣
mid_per_gas_ddc VARCHAR(100) DEFAULT '' COMMENT '中间业务_个人_煤气费代扣',
-- 中间业务_个人_市民卡
mid_per_citizencard VARCHAR(100) DEFAULT '' COMMENT '中间业务_个人_市民卡',
-- 中间业务_个人_理财业务
mid_per_fin_man VARCHAR(100) DEFAULT '' COMMENT '中间业务_个人_理财业务',
-- 中间业务_个人_etc
mid_per_etc VARCHAR(100) DEFAULT '' COMMENT '中间业务_个人_etc',
-- BP_中间业务
bp_mid VARCHAR(100) DEFAULT '' COMMENT 'BP_中间业务',
-- TOTAL_BP_关联度
totoal_bp_relevance VARCHAR(100) DEFAULT '' COMMENT 'TOTAL_BP_关联度',
-- 申请金额(元)
apply_amt VARCHAR(100) DEFAULT '' COMMENT '申请金额',
-- BP_贷款额度
bp_loan_amount VARCHAR(100) DEFAULT '' COMMENT 'BP_贷款额度',
-- 贷款用途(如:个人消费/经营)
loan_purpose VARCHAR(100) DEFAULT '' COMMENT '贷款用途',
-- 是否有经营佐证(是/否)
biz_proof VARCHAR(100) DEFAULT '' COMMENT '是否有经营佐证',
-- BP_贷款用途
bp_loan_use VARCHAR(100) DEFAULT '' COMMENT 'BP_贷款用途',
-- 循环功能(支持/不支持)
loan_loop VARCHAR(100) DEFAULT '' COMMENT '循环功能',
-- BP_循环功能
bp_loan_loop VARCHAR(100) DEFAULT '' COMMENT 'BP_循环功能',
-- 抵质押类型(如:无抵质押/房产抵押)
coll_type VARCHAR(100) DEFAULT '' COMMENT '抵质押类型',
-- 抵质押物是否三方所有(是/否)
coll_third_party VARCHAR(100) DEFAULT '' COMMENT '抵质押物是否三方所有',
-- BP_抵押物
bp_collateral VARCHAR(100) DEFAULT '' COMMENT 'BP_抵押物',
-- 灰名单客户(是/否)
grey_cust VARCHAR(100) DEFAULT '' COMMENT '灰名单客户',
-- 本金逾期(是/否)
prin_overdue VARCHAR(100) DEFAULT '' COMMENT '本金逾期',
-- 利息逾期(是/否)
interest_overdue VARCHAR(100) DEFAULT '' COMMENT '利息逾期',
-- 信用卡逾期(是/否)
card_overdue VARCHAR(100) DEFAULT '' COMMENT '信用卡逾期',
-- BP_灰名单与逾期
bp_grey_overdue VARCHAR(100) DEFAULT '' COMMENT 'BP_灰名单与逾期',
-- TOTAL_BP_风险度
totoal_bp_risk VARCHAR(100) DEFAULT '' COMMENT 'TOTAL_BP_风险度',
-- 浮动BP
total_bp VARCHAR(100) DEFAULT '' COMMENT '浮动BP',
-- 测算利率百分比如6.15
calculate_rate VARCHAR(100) DEFAULT '' COMMENT '测算利率',
-- 创建时间(审计字段)
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-- 主键约束
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='零售模型输出字段表';