Compare commits
11 Commits
739a73c6ee
...
892-withou
| Author | SHA1 | Date | |
|---|---|---|---|
| dd10192c18 | |||
| 3afff5d942 | |||
| b769180bb1 | |||
| cb29c38bf1 | |||
| 9552e2acb8 | |||
| a8ed8472f3 | |||
| 30a1d9771f | |||
| 6b5d31fb92 | |||
| 9d48d4b688 | |||
| 86b50f057e | |||
| 3667a3cf78 |
@@ -65,8 +65,16 @@ public class CorporateLoanPricingCreateDTO implements Serializable {
|
||||
@Schema(description = "贸易和建筑业企业标识", example = "0")
|
||||
private String isTradeBuildEnt;
|
||||
|
||||
@Schema(description = "抵质押类型", example = "一类", allowableValues = {"一类", "二类", "三类", "四类", "排污权抵押", "设备等其他不动产抵押", "存单质押", "股权质押", "其他质押"})
|
||||
@Pattern(regexp = "^(一类|二类|三类|四类|排污权抵押|设备等其他不动产抵押|存单质押|股权质押|其他质押)$", message = "抵质押类型必须是:一类、二类、三类、四类、排污权抵押、设备等其他不动产抵押、存单质押、股权质押、其他质押之一")
|
||||
@Schema(description = "抵押物性质", example = "普通住宅、土地、厂房", allowableValues = {"普通住宅、土地、厂房", "商业性质不动产", "排污权", "其他不动产"})
|
||||
@Pattern(regexp = "^(普通住宅、土地、厂房|商业性质不动产|排污权|其他不动产)$", message = "抵押物性质必须是:普通住宅、土地、厂房、商业性质不动产、排污权、其他不动产之一")
|
||||
private String collateralNature;
|
||||
|
||||
@Schema(description = "是否属于九地", example = "是", allowableValues = {"是", "否"})
|
||||
@Pattern(regexp = "^(是|否)$", message = "是否属于九地必须是:是、否之一")
|
||||
private String isNineArea;
|
||||
|
||||
@Schema(description = "抵质押类型", example = "一类", allowableValues = {"一类", "二类", "三类", "排污权抵押", "其他不动产抵押", "存单质押", "股权质押", "其他质押"})
|
||||
@Pattern(regexp = "^(一类|二类|三类|排污权抵押|其他不动产抵押|存单质押|股权质押|其他质押)$", message = "抵质押类型必须是:一类、二类、三类、排污权抵押、其他不动产抵押、存单质押、股权质押、其他质押之一")
|
||||
private String collType;
|
||||
|
||||
@Schema(description = "抵质押物是否三方所有", example = "0")
|
||||
|
||||
@@ -125,12 +125,12 @@ public class ModelInvokeDTO {
|
||||
|
||||
/**
|
||||
* 贷款用途(非必填)
|
||||
* 可选值:consumer/business
|
||||
* 可选值:经营/消费
|
||||
*/
|
||||
private String loanPurpose;
|
||||
|
||||
/**
|
||||
* 是否有经营佐证(非必填)
|
||||
* 是否有营业执照(非必填)
|
||||
* 可选值:0/1
|
||||
*/
|
||||
private String bizProof;
|
||||
|
||||
@@ -41,6 +41,11 @@ public class PersonalLoanPricingCreateDTO implements Serializable {
|
||||
@NotBlank(message = "申请金额不能为空")
|
||||
private String applyAmt;
|
||||
|
||||
@Schema(description = "贷款用途", requiredMode = Schema.RequiredMode.REQUIRED, example = "business", allowableValues = {"business", "consumer"})
|
||||
@NotBlank(message = "贷款用途不能为空")
|
||||
@Pattern(regexp = "^(business|consumer)$", message = "贷款用途必须是:business、consumer之一")
|
||||
private String loanPurpose;
|
||||
|
||||
@Schema(description = "业务种类", requiredMode = Schema.RequiredMode.REQUIRED, example = "存量转贷", allowableValues = {"新增", "存量新增", "存量转贷"})
|
||||
@NotBlank(message = "业务种类不能为空")
|
||||
@Pattern(regexp = "^(新增|存量新增|存量转贷)$", message = "业务种类必须是:新增、存量新增、存量转贷之一")
|
||||
@@ -53,10 +58,22 @@ public class PersonalLoanPricingCreateDTO implements Serializable {
|
||||
@NotBlank(message = "借款期限不能为空")
|
||||
private String loanTerm;
|
||||
|
||||
@Schema(description = "是否有营业执照", example = "0", allowableValues = {"0", "1"})
|
||||
@Pattern(regexp = "^[01]$", message = "是否有营业执照必须是:0或1")
|
||||
private String bizProof;
|
||||
|
||||
@Schema(description = "循环功能", example = "0")
|
||||
private String loanLoop;
|
||||
|
||||
@Schema(description = "抵质押类型", example = "一类", allowableValues = {"一线", "一类", "二类", "三类", "存单质押", "其他质押"})
|
||||
@Schema(description = "抵押物性质", example = "普通住宅、土地、厂房", allowableValues = {"普通住宅、土地、厂房", "商业性质不动产", "其他抵押财产"})
|
||||
@Pattern(regexp = "^(普通住宅、土地、厂房|商业性质不动产|其他抵押财产)$", message = "抵押物性质必须是:普通住宅、土地、厂房、商业性质不动产、其他抵押财产之一")
|
||||
private String collateralNature;
|
||||
|
||||
@Schema(description = "是否属于九地", example = "是", allowableValues = {"是", "否"})
|
||||
@Pattern(regexp = "^(是|否)$", message = "是否属于九地必须是:是、否之一")
|
||||
private String isNineArea;
|
||||
|
||||
@Schema(description = "抵质押类型", example = "一类", allowableValues = {"一类", "二类", "三类", "四类", "存单质押", "其他质押"})
|
||||
private String collType;
|
||||
|
||||
@Schema(description = "抵质押物是否三方所有", example = "0")
|
||||
|
||||
@@ -116,7 +116,7 @@ public class LoanPricingWorkflow implements Serializable
|
||||
/** 余值覆盖: 0/1 */
|
||||
private String resCover;
|
||||
|
||||
/** 是否有经营佐证: true/false */
|
||||
/** 是否有营业执照: true/false */
|
||||
private String bizProof;
|
||||
|
||||
/** 循环功能: true/false */
|
||||
@@ -125,6 +125,12 @@ public class LoanPricingWorkflow implements Serializable
|
||||
/** 抵质押类型: 一类/二类/三类/四类 */
|
||||
private String collType;
|
||||
|
||||
/** 抵押物性质 */
|
||||
private String collateralNature;
|
||||
|
||||
/** 是否属于九地: 是/否 */
|
||||
private String isNineArea;
|
||||
|
||||
/** 抵质押物是否三方所有: true/false */
|
||||
private String collThirdParty;
|
||||
|
||||
|
||||
@@ -106,10 +106,20 @@ public class ModelCorpOutputFields {
|
||||
private String bpCollateral;
|
||||
// 灰名单客户
|
||||
private String greyCust;
|
||||
// 黑名单客户
|
||||
private String blackCust;
|
||||
// 本金逾期
|
||||
private String prinOverdue;
|
||||
// BP_本金逾期
|
||||
private String bpPrinOverdue;
|
||||
// 利息逾期
|
||||
private String interestOverdue;
|
||||
// BP_利息逾期
|
||||
private String bpIinterestOverdue;
|
||||
// 信用卡逾期
|
||||
private String cardOverdue;
|
||||
// BP_信用卡逾期
|
||||
private String bpCardOverdue;
|
||||
// BP_灰名单与逾期
|
||||
private String bpGreyOverdue;
|
||||
// TOTAL_BP_风险度
|
||||
@@ -129,6 +139,8 @@ public class ModelCorpOutputFields {
|
||||
private String finalCalculateRate;
|
||||
// 参考利率
|
||||
private String referenceRate;
|
||||
// 行社下调BP
|
||||
private String branchBp;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Date createTime;
|
||||
|
||||
@@ -129,7 +129,7 @@ public class ModelRetailOutputFields {
|
||||
// 贷款用途
|
||||
private String loanPurpose;
|
||||
|
||||
// 是否有经营佐证
|
||||
// 是否有营业执照
|
||||
private String bizProof;
|
||||
|
||||
// BP_贷款用途
|
||||
@@ -153,15 +153,27 @@ public class ModelRetailOutputFields {
|
||||
// 灰名单客户
|
||||
private String greyCust;
|
||||
|
||||
// 黑名单客户
|
||||
private String blackCust;
|
||||
|
||||
// 本金逾期
|
||||
private String prinOverdue;
|
||||
|
||||
// BP_本金逾期
|
||||
private String bpPrinOverdue;
|
||||
|
||||
// 利息逾期
|
||||
private String interestOverdue;
|
||||
|
||||
// BP_利息逾期
|
||||
private String bpIinterestOverdue;
|
||||
|
||||
// 信用卡逾期
|
||||
private String cardOverdue;
|
||||
|
||||
// BP_信用卡逾期
|
||||
private String bpCardOverdue;
|
||||
|
||||
// BP_灰名单与逾期
|
||||
private String bpGreyOverdue;
|
||||
|
||||
@@ -190,6 +202,9 @@ public class ModelRetailOutputFields {
|
||||
// 参考利率
|
||||
private String referenceRate;
|
||||
|
||||
// 行社下调BP
|
||||
private String branchBp;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Date createTime;
|
||||
}
|
||||
|
||||
@@ -102,11 +102,25 @@ public class LoanPricingModelService {
|
||||
|
||||
private void normalizePersonalModelInvokeDTO(ModelInvokeDTO modelInvokeDTO)
|
||||
{
|
||||
modelInvokeDTO.setLoanPurpose(toPersonalModelLoanPurpose(modelInvokeDTO.getLoanPurpose()));
|
||||
modelInvokeDTO.setBizProof(toZeroOne(modelInvokeDTO.getBizProof()));
|
||||
modelInvokeDTO.setLoanLoop(toZeroOne(modelInvokeDTO.getLoanLoop()));
|
||||
modelInvokeDTO.setCollThirdParty(toZeroOne(modelInvokeDTO.getCollThirdParty()));
|
||||
}
|
||||
|
||||
private String toPersonalModelLoanPurpose(String value)
|
||||
{
|
||||
if ("business".equals(value))
|
||||
{
|
||||
return "经营";
|
||||
}
|
||||
if ("consumer".equals(value))
|
||||
{
|
||||
return "消费";
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private void normalizeCorporateModelInvokeDTO(ModelInvokeDTO modelInvokeDTO)
|
||||
{
|
||||
modelInvokeDTO.setCollThirdParty(toZeroOne(modelInvokeDTO.getCollThirdParty()));
|
||||
|
||||
@@ -139,8 +139,8 @@ public class LoanPricingWorkflowServiceImpl implements ILoanPricingWorkflowServi
|
||||
|
||||
private void validatePersonalCollateralType(LoanPricingWorkflow workflow) {
|
||||
if ("抵押".equals(workflow.getGuarType())
|
||||
&& !isOneOf(workflow.getCollType(), "一线", "一类", "二类", "三类")) {
|
||||
throw new ServiceException("个人抵押抵质押类型必须是:一线、一类、二类、三类之一");
|
||||
&& !isOneOf(workflow.getCollType(), "一类", "二类", "三类", "四类")) {
|
||||
throw new ServiceException("个人抵押抵质押类型必须是:一类、二类、三类、四类之一");
|
||||
}
|
||||
if ("质押".equals(workflow.getGuarType())
|
||||
&& !isOneOf(workflow.getCollType(), "存单质押", "其他质押")) {
|
||||
@@ -150,8 +150,8 @@ public class LoanPricingWorkflowServiceImpl implements ILoanPricingWorkflowServi
|
||||
|
||||
private void validateCorporateCollateralType(LoanPricingWorkflow workflow) {
|
||||
if ("抵押".equals(workflow.getGuarType())
|
||||
&& !isOneOf(workflow.getCollType(), "一类", "二类", "三类", "四类", "排污权抵押", "设备等其他不动产抵押")) {
|
||||
throw new ServiceException("企业抵押抵质押类型必须是:一类、二类、三类、四类、排污权抵押、设备等其他不动产抵押之一");
|
||||
&& !isOneOf(workflow.getCollType(), "一类", "二类", "三类", "排污权抵押", "其他不动产抵押")) {
|
||||
throw new ServiceException("企业抵押抵质押类型必须是:一类、二类、三类、排污权抵押、其他不动产抵押之一");
|
||||
}
|
||||
if ("质押".equals(workflow.getGuarType())
|
||||
&& !isOneOf(workflow.getCollType(), "存单质押", "股权质押", "其他质押")) {
|
||||
@@ -242,12 +242,16 @@ public class LoanPricingWorkflowServiceImpl implements ILoanPricingWorkflowServi
|
||||
.set(LoanPricingWorkflow::getIdNum, editingWorkflow.getIdNum())
|
||||
.set(LoanPricingWorkflow::getGuarType, editingWorkflow.getGuarType())
|
||||
.set(LoanPricingWorkflow::getApplyAmt, editingWorkflow.getApplyAmt())
|
||||
.set(LoanPricingWorkflow::getLoanPurpose, editingWorkflow.getLoanPurpose())
|
||||
.set(LoanPricingWorkflow::getBusinessType, editingWorkflow.getBusinessType())
|
||||
.set(LoanPricingWorkflow::getLoanRateHistory, editingWorkflow.getLoanRateHistory())
|
||||
.set(LoanPricingWorkflow::getCouponRate, editingWorkflow.getCouponRate())
|
||||
.set(LoanPricingWorkflow::getLoanTerm, editingWorkflow.getLoanTerm())
|
||||
.set(LoanPricingWorkflow::getCollateralNature, editingWorkflow.getCollateralNature())
|
||||
.set(LoanPricingWorkflow::getIsNineArea, editingWorkflow.getIsNineArea())
|
||||
.set(LoanPricingWorkflow::getCollType, editingWorkflow.getCollType())
|
||||
.set(LoanPricingWorkflow::getCollThirdParty, editingWorkflow.getCollThirdParty())
|
||||
.set(LoanPricingWorkflow::getBizProof, editingWorkflow.getBizProof())
|
||||
.set(LoanPricingWorkflow::getLoanLoop, editingWorkflow.getLoanLoop())
|
||||
.set(LoanPricingWorkflow::getResCover, editingWorkflow.getResCover())
|
||||
.set(LoanPricingWorkflow::getRepayMethod, editingWorkflow.getRepayMethod())
|
||||
|
||||
@@ -28,13 +28,17 @@ public class LoanPricingConverter {
|
||||
entity.setIdNum(dto.getIdNum());
|
||||
entity.setGuarType(dto.getGuarType());
|
||||
entity.setApplyAmt(dto.getApplyAmt());
|
||||
entity.setLoanPurpose(dto.getLoanPurpose());
|
||||
entity.setBusinessType(dto.getBusinessType());
|
||||
entity.setLoanRateHistory(dto.getLoanRateHistory());
|
||||
entity.setCouponRate(dto.getCouponRate());
|
||||
entity.setLoanTerm(dto.getLoanTerm());
|
||||
entity.setCollateralNature(dto.getCollateralNature());
|
||||
entity.setIsNineArea(dto.getIsNineArea());
|
||||
entity.setCollType(dto.getCollType());
|
||||
entity.setCollThirdParty(dto.getCollThirdParty());
|
||||
// 映射个人特有字段
|
||||
entity.setBizProof(dto.getBizProof());
|
||||
entity.setLoanLoop(dto.getLoanLoop());
|
||||
return entity;
|
||||
}
|
||||
@@ -60,6 +64,8 @@ public class LoanPricingConverter {
|
||||
entity.setCouponRate(dto.getCouponRate());
|
||||
entity.setResCover(dto.getResCover());
|
||||
entity.setRepayMethod(dto.getRepayMethod());
|
||||
entity.setCollateralNature(dto.getCollateralNature());
|
||||
entity.setIsNineArea(dto.getIsNineArea());
|
||||
entity.setCollType(dto.getCollType());
|
||||
entity.setCollThirdParty(dto.getCollThirdParty());
|
||||
entity.setIsGreenLoan(dto.getIsGreenLoan());
|
||||
|
||||
@@ -20,13 +20,13 @@
|
||||
"loanAvg": "3000000.00",
|
||||
"derivationRate": "1.8",
|
||||
"totalBpContribution": "12.3",
|
||||
"midEntConnect": "1",
|
||||
"midEntEffect": "1",
|
||||
"midEntInter": "1",
|
||||
"midEntAccept": "1",
|
||||
"midEntDiscount": "1",
|
||||
"midEntEleDdc": "1",
|
||||
"midEntWaterDdc": "1",
|
||||
"midEntConnect": "-2",
|
||||
"midEntEffect": "0",
|
||||
"midEntInter": "-3",
|
||||
"midEntAccept": "0",
|
||||
"midEntDiscount": "-1",
|
||||
"midEntEleDdc": "0",
|
||||
"midEntWaterDdc": "-1",
|
||||
"bpMid": "6.8",
|
||||
"payroll": "200",
|
||||
"invLoanAmount": "2500000.00",
|
||||
@@ -45,8 +45,13 @@
|
||||
"collThirdParty": "0",
|
||||
"bpCollateral": "4.5",
|
||||
"greyCust": "0",
|
||||
"blackCust": "1",
|
||||
"prinOverdue": "0",
|
||||
"interestOverdue": "0",
|
||||
"bpPrinOverdue": "0",
|
||||
"interestOverdue": "3",
|
||||
"bpIinterestOverdue": "0",
|
||||
"cardOverdue": "0",
|
||||
"bpCardOverdue": "0",
|
||||
"bpGreyOverdue": "0",
|
||||
"totalBpRisk": "1.2",
|
||||
"totalBp": "48.2",
|
||||
@@ -56,7 +61,8 @@
|
||||
"minRateProduct": "3.10",
|
||||
"smoothRange": "-0.20",
|
||||
"finalCalculateRate": "3.732",
|
||||
"referenceRate": "3.432"
|
||||
"referenceRate": "3.432",
|
||||
"branchBp": "-5"
|
||||
},
|
||||
"extensionMap": {},
|
||||
"reasonMessage": "Running successfully",
|
||||
|
||||
@@ -22,18 +22,18 @@
|
||||
"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",
|
||||
"midPerCard": "-2",
|
||||
"midPerPass": "0",
|
||||
"midPerHarvest": "-3",
|
||||
"midPerEffect": "0",
|
||||
"midPerQuickPay": "-1",
|
||||
"midPerEleDdc": "0",
|
||||
"midPerWaterDdc": "-1",
|
||||
"midPerHuashuDdc": "0",
|
||||
"MidPerGasDdc": "-1",
|
||||
"midPerCitizencard": "0",
|
||||
"midPerFinMan": "-4",
|
||||
"midPerEtc": "0",
|
||||
"bpMid": "45",
|
||||
"totalBpRelevance": "90",
|
||||
"applyAmt": "200000.00",
|
||||
@@ -47,9 +47,13 @@
|
||||
"collThirdParty": "否",
|
||||
"bpCollateral": "0",
|
||||
"greyCust": "否",
|
||||
"blackCust": "否",
|
||||
"prinOverdue": "否",
|
||||
"bpPrinOverdue": "0",
|
||||
"interestOverdue": "否",
|
||||
"bpIinterestOverdue": "0",
|
||||
"cardOverdue": "否",
|
||||
"bpCardOverdue": "0",
|
||||
"bpGreyOverdue": "98",
|
||||
"totalBpRisk": "95",
|
||||
"totalBp": "350",
|
||||
@@ -58,7 +62,8 @@
|
||||
"minRateProduct": "5.50",
|
||||
"smoothRange": "-0.10",
|
||||
"finalCalculateRate": "6.05",
|
||||
"referenceRate": "5.95"
|
||||
"referenceRate": "5.95",
|
||||
"branchBp": "-8"
|
||||
},
|
||||
"extensionMap": {},
|
||||
"reasonMessage": "Running successfully",
|
||||
|
||||
@@ -23,5 +23,10 @@ class ModelRetailOutputFieldsTest
|
||||
assertTrue(fieldNames.contains("finalCalculateRate"), "缺少字段 finalCalculateRate");
|
||||
assertTrue(fieldNames.contains("referenceRate"), "缺少字段 referenceRate");
|
||||
assertTrue(fieldNames.contains("greyBlackCust"), "缺少字段 greyBlackCust");
|
||||
assertTrue(fieldNames.contains("blackCust"), "缺少字段 blackCust");
|
||||
assertTrue(fieldNames.contains("branchBp"), "缺少字段 branchBp");
|
||||
assertTrue(fieldNames.contains("bpPrinOverdue"), "缺少字段 bpPrinOverdue");
|
||||
assertTrue(fieldNames.contains("bpIinterestOverdue"), "缺少字段 bpIinterestOverdue");
|
||||
assertTrue(fieldNames.contains("bpCardOverdue"), "缺少字段 bpCardOverdue");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,6 @@ import java.util.Objects;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -44,28 +42,28 @@ class LoanPricingModelServicePersonalParamsTest {
|
||||
private LoanPricingModelService loanPricingModelService;
|
||||
|
||||
@Test
|
||||
void shouldRemoveLoanPurposeAndKeepLoanTermInPersonalCreateDto() throws NoSuchFieldException {
|
||||
assertThrows(NoSuchFieldException.class,
|
||||
() -> PersonalLoanPricingCreateDTO.class.getDeclaredField("loanPurpose"));
|
||||
assertThrows(NoSuchFieldException.class,
|
||||
() -> PersonalLoanPricingCreateDTO.class.getDeclaredField("bizProof"));
|
||||
void shouldContainLoanPurposeAndPersonalModelFieldsInCreateDto() throws NoSuchFieldException {
|
||||
assertNotNull(PersonalLoanPricingCreateDTO.class.getDeclaredField("loanPurpose"));
|
||||
assertNotNull(PersonalLoanPricingCreateDTO.class.getDeclaredField("bizProof"));
|
||||
assertNotNull(PersonalLoanPricingCreateDTO.class.getDeclaredField("loanTerm"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotMapLoanPurposeAndBizProofFromPersonalDto() {
|
||||
void shouldMapLoanPurposeAndBizProofFromPersonalDto() {
|
||||
PersonalLoanPricingCreateDTO dto = new PersonalLoanPricingCreateDTO();
|
||||
dto.setCustIsn("CUST001");
|
||||
dto.setCustName("张三");
|
||||
dto.setGuarType("信用");
|
||||
dto.setApplyAmt("100000");
|
||||
dto.setLoanPurpose("business");
|
||||
dto.setBusinessType("新增");
|
||||
dto.setLoanTerm("3");
|
||||
dto.setBizProof("1");
|
||||
|
||||
LoanPricingWorkflow workflow = LoanPricingConverter.toEntity(dto);
|
||||
|
||||
assertNull(workflow.getLoanPurpose());
|
||||
assertNull(workflow.getBizProof());
|
||||
assertEquals("business", workflow.getLoanPurpose());
|
||||
assertEquals("1", workflow.getBizProof());
|
||||
assertEquals("3", workflow.getLoanTerm());
|
||||
}
|
||||
|
||||
@@ -89,7 +87,9 @@ class LoanPricingModelServicePersonalParamsTest {
|
||||
workflow.setIdNum("110101199001011234");
|
||||
workflow.setGuarType("信用");
|
||||
workflow.setApplyAmt("100000");
|
||||
workflow.setLoanPurpose("consumer");
|
||||
workflow.setLoanTerm("3");
|
||||
workflow.setBizProof("true");
|
||||
workflow.setLoanLoop("false");
|
||||
workflow.setCollThirdParty("true");
|
||||
workflow.setCollType("一类");
|
||||
@@ -113,9 +113,27 @@ class LoanPricingModelServicePersonalParamsTest {
|
||||
&& Objects.equals("110101199001011234", dto.getIdNum())
|
||||
&& Objects.equals("信用", dto.getGuarType())
|
||||
&& Objects.equals("100000", dto.getApplyAmt())
|
||||
&& Objects.equals("消费", dto.getLoanPurpose())
|
||||
&& Objects.equals("3", dto.getLoanTerm())
|
||||
&& Objects.equals("1", dto.getBizProof())
|
||||
&& Objects.equals("0", dto.getLoanLoop())
|
||||
&& Objects.equals("1", dto.getCollThirdParty())
|
||||
&& Objects.equals("一类", dto.getCollType())));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldConvertBusinessLoanPurposeForPersonalModel() {
|
||||
LoanPricingWorkflow workflow = new LoanPricingWorkflow();
|
||||
workflow.setId(2L);
|
||||
workflow.setCustType("个人");
|
||||
workflow.setLoanPurpose("business");
|
||||
|
||||
when(loanPricingWorkflowMapper.selectById(2L)).thenReturn(workflow);
|
||||
when(modelService.invokePersonalModel(any())).thenReturn(new ModelRetailOutputFields());
|
||||
|
||||
loanPricingModelService.invokeModelAsync(2L);
|
||||
|
||||
verify(modelService).invokePersonalModel(argThat((ModelInvokeDTO dto) ->
|
||||
Objects.equals("经营", dto.getLoanPurpose())));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ class LoanPricingModelServiceTest
|
||||
assertEquals("张三", context.modelService.personalRequest.getCustName());
|
||||
assertEquals("110101199001011234", context.modelService.personalRequest.getIdNum());
|
||||
assertEquals("2.15", context.modelService.personalRequest.getCouponRate());
|
||||
assertEquals("1", context.modelService.personalRequest.getBizProof());
|
||||
assertEquals(1, context.modelService.personalCalls.get());
|
||||
assertEquals(0, context.modelService.corporateCalls.get());
|
||||
assertEquals(1, context.retailInsertCount.get());
|
||||
@@ -105,6 +106,7 @@ class LoanPricingModelServiceTest
|
||||
workflow.setCustName("张三");
|
||||
workflow.setIdNum("110101199001011234");
|
||||
workflow.setCouponRate("2.15");
|
||||
workflow.setBizProof("true");
|
||||
return workflow;
|
||||
}
|
||||
|
||||
|
||||
@@ -290,36 +290,67 @@ class LoanPricingWorkflowServiceImplTest
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAllowPersonalMortgageOneLineAndRejectOldOther()
|
||||
void shouldAllowPersonalMortgageFourthCategoryAndRejectOldFirstLine()
|
||||
{
|
||||
LoanPricingWorkflow allowedWorkflow = validWorkflow();
|
||||
allowedWorkflow.setCustType("个人");
|
||||
allowedWorkflow.setGuarType("抵押");
|
||||
allowedWorkflow.setCollType("一线");
|
||||
allowedWorkflow.setCollType("四类");
|
||||
|
||||
loanPricingWorkflowService.createLoanPricing(allowedWorkflow);
|
||||
|
||||
LoanPricingWorkflow rejectedWorkflow = validWorkflow();
|
||||
rejectedWorkflow.setCustType("个人");
|
||||
rejectedWorkflow.setGuarType("抵押");
|
||||
rejectedWorkflow.setCollType("其他");
|
||||
rejectedWorkflow.setCollType("一线");
|
||||
|
||||
ServiceException exception = assertThrows(ServiceException.class,
|
||||
() -> loanPricingWorkflowService.createLoanPricing(rejectedWorkflow));
|
||||
|
||||
assertEquals("个人抵押抵质押类型必须是:一线、一类、二类、三类之一", exception.getMessage());
|
||||
assertEquals("个人抵押抵质押类型必须是:一类、二类、三类、四类之一", exception.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAllowCorporateMortgagePollutionRightAndPledgeEquity()
|
||||
void shouldAllowCorporateNewMortgageTypesAndRejectOldMortgageTypes()
|
||||
{
|
||||
LoanPricingWorkflow mortgageWorkflow = validWorkflow();
|
||||
mortgageWorkflow.setCustType("企业");
|
||||
mortgageWorkflow.setGuarType("抵押");
|
||||
mortgageWorkflow.setCollType("排污权抵押");
|
||||
LoanPricingWorkflow pollutionRightWorkflow = validWorkflow();
|
||||
pollutionRightWorkflow.setCustType("企业");
|
||||
pollutionRightWorkflow.setGuarType("抵押");
|
||||
pollutionRightWorkflow.setCollType("排污权抵押");
|
||||
|
||||
loanPricingWorkflowService.createLoanPricing(mortgageWorkflow);
|
||||
loanPricingWorkflowService.createLoanPricing(pollutionRightWorkflow);
|
||||
|
||||
LoanPricingWorkflow otherRealEstateWorkflow = validWorkflow();
|
||||
otherRealEstateWorkflow.setCustType("企业");
|
||||
otherRealEstateWorkflow.setGuarType("抵押");
|
||||
otherRealEstateWorkflow.setCollType("其他不动产抵押");
|
||||
|
||||
loanPricingWorkflowService.createLoanPricing(otherRealEstateWorkflow);
|
||||
|
||||
LoanPricingWorkflow oldFourthCategoryWorkflow = validWorkflow();
|
||||
oldFourthCategoryWorkflow.setCustType("企业");
|
||||
oldFourthCategoryWorkflow.setGuarType("抵押");
|
||||
oldFourthCategoryWorkflow.setCollType("四类");
|
||||
|
||||
ServiceException fourthCategoryException = assertThrows(ServiceException.class,
|
||||
() -> loanPricingWorkflowService.createLoanPricing(oldFourthCategoryWorkflow));
|
||||
|
||||
LoanPricingWorkflow oldOtherRealEstateWorkflow = validWorkflow();
|
||||
oldOtherRealEstateWorkflow.setCustType("企业");
|
||||
oldOtherRealEstateWorkflow.setGuarType("抵押");
|
||||
oldOtherRealEstateWorkflow.setCollType("设备等其他不动产抵押");
|
||||
|
||||
ServiceException otherRealEstateException = assertThrows(ServiceException.class,
|
||||
() -> loanPricingWorkflowService.createLoanPricing(oldOtherRealEstateWorkflow));
|
||||
|
||||
String expectedMessage = "企业抵押抵质押类型必须是:一类、二类、三类、排污权抵押、其他不动产抵押之一";
|
||||
assertEquals(expectedMessage, fourthCategoryException.getMessage());
|
||||
assertEquals(expectedMessage, otherRealEstateException.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldKeepCorporatePledgeTypesUnchanged()
|
||||
{
|
||||
LoanPricingWorkflow pledgeWorkflow = validWorkflow();
|
||||
pledgeWorkflow.setCustType("企业");
|
||||
pledgeWorkflow.setGuarType("质押");
|
||||
@@ -339,7 +370,7 @@ class LoanPricingWorkflowServiceImplTest
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldCreatePersonalWorkflowWithCouponRateAndWithoutRemovedFields()
|
||||
void shouldCreatePersonalWorkflowWithCouponRateAndBizProof()
|
||||
{
|
||||
PersonalLoanPricingCreateDTO dto = new PersonalLoanPricingCreateDTO();
|
||||
dto.setCustIsn("CUST001");
|
||||
@@ -349,6 +380,7 @@ class LoanPricingWorkflowServiceImplTest
|
||||
dto.setLoanTerm("3");
|
||||
dto.setCollType("存单质押");
|
||||
dto.setCouponRate("2.15");
|
||||
dto.setBizProof("1");
|
||||
|
||||
loanPricingWorkflowService.createPersonalLoanPricing(dto);
|
||||
|
||||
@@ -356,7 +388,7 @@ class LoanPricingWorkflowServiceImplTest
|
||||
Objects.equals("个人", entity.getCustType())
|
||||
&& Objects.equals("2.15", entity.getCouponRate())
|
||||
&& Objects.isNull(entity.getLoanPurpose())
|
||||
&& Objects.isNull(entity.getBizProof())));
|
||||
&& Objects.equals("1", entity.getBizProof())));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -381,6 +413,48 @@ class LoanPricingWorkflowServiceImplTest
|
||||
&& Objects.equals("2.35", entity.getCouponRate())));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldCreatePersonalWorkflowWithMortgageSourceFields()
|
||||
{
|
||||
PersonalLoanPricingCreateDTO dto = new PersonalLoanPricingCreateDTO();
|
||||
dto.setCustIsn("CUST001");
|
||||
dto.setGuarType("抵押");
|
||||
dto.setApplyAmt("100000");
|
||||
dto.setBusinessType("新增");
|
||||
dto.setLoanTerm("3");
|
||||
dto.setCollateralNature("普通住宅、土地、厂房");
|
||||
dto.setIsNineArea("是");
|
||||
dto.setCollType("一类");
|
||||
|
||||
loanPricingWorkflowService.createPersonalLoanPricing(dto);
|
||||
|
||||
verify(loanPricingWorkflowMapper).insert(argThat((LoanPricingWorkflow entity) ->
|
||||
Objects.equals("普通住宅、土地、厂房", entity.getCollateralNature())
|
||||
&& Objects.equals("是", entity.getIsNineArea())
|
||||
&& Objects.equals("一类", entity.getCollType())));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldCreateCorporateWorkflowWithMortgageSourceFields()
|
||||
{
|
||||
CorporateLoanPricingCreateDTO dto = new CorporateLoanPricingCreateDTO();
|
||||
dto.setCustIsn("CORP001");
|
||||
dto.setGuarType("抵押");
|
||||
dto.setApplyAmt("1000000");
|
||||
dto.setBusinessType("新增");
|
||||
dto.setLoanTerm("5");
|
||||
dto.setCollateralNature("商业性质不动产");
|
||||
dto.setIsNineArea("否");
|
||||
dto.setCollType("三类");
|
||||
|
||||
loanPricingWorkflowService.createCorporateLoanPricing(dto);
|
||||
|
||||
verify(loanPricingWorkflowMapper).insert(argThat((LoanPricingWorkflow entity) ->
|
||||
Objects.equals("商业性质不动产", entity.getCollateralNature())
|
||||
&& Objects.equals("否", entity.getIsNineArea())
|
||||
&& Objects.equals("三类", entity.getCollType())));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnEditableWorkflowWithPlainSensitiveFieldsForCreator()
|
||||
{
|
||||
@@ -420,11 +494,16 @@ class LoanPricingWorkflowServiceImplTest
|
||||
dto.setCustName("张三");
|
||||
dto.setIdType("身份证");
|
||||
dto.setIdNum("110101199001019999");
|
||||
dto.setGuarType("信用");
|
||||
dto.setGuarType("抵押");
|
||||
dto.setApplyAmt("200000");
|
||||
dto.setLoanPurpose("business");
|
||||
dto.setBusinessType("新增");
|
||||
dto.setLoanTerm("3");
|
||||
dto.setLoanLoop("1");
|
||||
dto.setBizProof("1");
|
||||
dto.setCollateralNature("普通住宅、土地、厂房");
|
||||
dto.setIsNineArea("是");
|
||||
dto.setCollType("一类");
|
||||
|
||||
loanPricingWorkflowService.updatePersonalLoanPricing("P20260525001", dto);
|
||||
|
||||
@@ -432,10 +511,18 @@ class LoanPricingWorkflowServiceImplTest
|
||||
verify(loanPricingWorkflowMapper).update(any(), updateWrapperCaptor.capture());
|
||||
String sqlSet = updateWrapperCaptor.getValue().getSqlSet();
|
||||
assertTrue(sqlSet.contains("apply_amt"));
|
||||
assertTrue(sqlSet.contains("loan_purpose"));
|
||||
assertTrue(sqlSet.contains("cust_name"));
|
||||
assertTrue(sqlSet.contains("id_num"));
|
||||
assertTrue(sqlSet.contains("biz_proof"));
|
||||
assertTrue(sqlSet.contains("collateral_nature"));
|
||||
assertTrue(sqlSet.contains("is_nine_area"));
|
||||
assertTrue(updateWrapperCaptor.getValue().getParamNameValuePairs().containsValue("张三"));
|
||||
assertTrue(updateWrapperCaptor.getValue().getParamNameValuePairs().containsValue("110101199001019999"));
|
||||
assertTrue(updateWrapperCaptor.getValue().getParamNameValuePairs().containsValue("普通住宅、土地、厂房"));
|
||||
assertTrue(updateWrapperCaptor.getValue().getParamNameValuePairs().containsValue("business"));
|
||||
assertTrue(updateWrapperCaptor.getValue().getParamNameValuePairs().containsValue("是"));
|
||||
assertTrue(updateWrapperCaptor.getValue().getParamNameValuePairs().containsValue("1"));
|
||||
verify(sensitiveFieldCryptoService, never()).encrypt(any());
|
||||
verify(loanPricingModelService).reinvokeModelAndOverwrite(101L);
|
||||
}
|
||||
|
||||
@@ -100,7 +100,33 @@
|
||||
<!-- 抵质押信息 -->
|
||||
<el-divider v-if="isCollateralGuarantee" content-position="left">抵质押信息</el-divider>
|
||||
<el-row v-if="isCollateralGuarantee">
|
||||
<el-col :span="12">
|
||||
<template v-if="isMortgage">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="抵押物性质" prop="collateralNature">
|
||||
<el-select v-model="form.collateralNature" placeholder="请选择抵押物性质" style="width: 100%">
|
||||
<el-option v-for="item in collateralNatureOptions" :key="item" :label="item" :value="item"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="是否属于九地" prop="isNineArea">
|
||||
<div class="nine-area-control">
|
||||
<el-select
|
||||
v-model="form.isNineArea"
|
||||
:disabled="!requiresNineArea"
|
||||
:placeholder="requiresNineArea ? '请选择是否属于九地' : '无需选择'"
|
||||
>
|
||||
<el-option label="是" value="是"/>
|
||||
<el-option label="否" value="否"/>
|
||||
</el-select>
|
||||
<el-tooltip content="九地是指绍兴、杭州、宁波、上海、北京、广州、深圳、南京、苏州" placement="top">
|
||||
<i class="el-icon-question nine-area-help" tabindex="0" aria-label="查看九地说明"></i>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</template>
|
||||
<el-col :span="12" v-if="isPledge">
|
||||
<el-form-item label="抵质押类型" prop="collType">
|
||||
<el-select v-model="form.collType" placeholder="请选择抵质押类型" style="width: 100%">
|
||||
<el-option v-for="item in collateralTypeOptions" :key="item" :label="item" :value="item"/>
|
||||
@@ -181,6 +207,30 @@ export default {
|
||||
callback()
|
||||
}
|
||||
|
||||
const validateCollateralType = (rule, value, callback) => {
|
||||
if (this.isPledge && !value) {
|
||||
callback(new Error('请选择抵质押类型'))
|
||||
return
|
||||
}
|
||||
callback()
|
||||
}
|
||||
|
||||
const validateCollateralNature = (rule, value, callback) => {
|
||||
if (this.isMortgage && !value) {
|
||||
callback(new Error('请选择抵押物性质'))
|
||||
return
|
||||
}
|
||||
callback()
|
||||
}
|
||||
|
||||
const validateNineArea = (rule, value, callback) => {
|
||||
if (this.requiresNineArea && !value) {
|
||||
callback(new Error('请选择是否属于九地'))
|
||||
return
|
||||
}
|
||||
callback()
|
||||
}
|
||||
|
||||
// 贷款期限验证
|
||||
const validateLoanTerm = (rule, value, callback) => {
|
||||
if (!value && value !== 0) {
|
||||
@@ -221,6 +271,8 @@ export default {
|
||||
isGreenLoan: false,
|
||||
isTradeBuildEnt: false,
|
||||
collType: undefined,
|
||||
collateralNature: undefined,
|
||||
isNineArea: undefined,
|
||||
collThirdParty: false,
|
||||
couponRate: undefined
|
||||
},
|
||||
@@ -255,7 +307,13 @@ export default {
|
||||
{required: true, message: "请选择历史贷款合同", trigger: "change"}
|
||||
],
|
||||
collType: [
|
||||
{required: true, message: "请选择抵质押类型", trigger: "change"}
|
||||
{validator: validateCollateralType, trigger: "change"}
|
||||
],
|
||||
collateralNature: [
|
||||
{validator: validateCollateralNature, trigger: "change"}
|
||||
],
|
||||
isNineArea: [
|
||||
{validator: validateNineArea, trigger: "change"}
|
||||
],
|
||||
couponRate: [
|
||||
{validator: validateCouponRate, trigger: "blur"}
|
||||
@@ -275,6 +333,15 @@ export default {
|
||||
isCollateralGuarantee() {
|
||||
return this.form.guarType === '抵押' || this.form.guarType === '质押'
|
||||
},
|
||||
isMortgage() {
|
||||
return this.form.guarType === '抵押'
|
||||
},
|
||||
isPledge() {
|
||||
return this.form.guarType === '质押'
|
||||
},
|
||||
requiresNineArea() {
|
||||
return this.isMortgage && ['普通住宅、土地、厂房', '商业性质不动产'].includes(this.form.collateralNature)
|
||||
},
|
||||
isStockTransfer() {
|
||||
return this.form.businessType === '存量转贷'
|
||||
},
|
||||
@@ -288,13 +355,13 @@ export default {
|
||||
return this.isEdit ? '编辑企业利率定价流程' : '新增企业利率定价流程'
|
||||
},
|
||||
collateralTypeOptions() {
|
||||
if (this.form.guarType === '抵押') {
|
||||
return ['一类', '二类', '三类', '四类', '排污权抵押', '设备等其他不动产抵押']
|
||||
}
|
||||
if (this.form.guarType === '质押') {
|
||||
if (this.isPledge) {
|
||||
return ['存单质押', '股权质押', '其他质押']
|
||||
}
|
||||
return []
|
||||
},
|
||||
collateralNatureOptions() {
|
||||
return ['普通住宅、土地、厂房', '商业性质不动产', '排污权', '其他不动产']
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -316,6 +383,12 @@ export default {
|
||||
return
|
||||
}
|
||||
this.resetCouponRateIfNotCertificatePledge()
|
||||
},
|
||||
'form.collateralNature'(val, oldVal) {
|
||||
if (this.resettingForm || val === oldVal) {
|
||||
return
|
||||
}
|
||||
this.handleCollateralNatureChange()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -353,7 +426,9 @@ export default {
|
||||
resCover: this.isOne(this.editData.resCover),
|
||||
isGreenLoan: this.isOne(this.editData.isGreenLoan),
|
||||
isTradeBuildEnt: this.isOne(this.editData.isTradeBuildEnt),
|
||||
collType: this.editData.collType,
|
||||
collType: this.editData.guarType === '质押' ? this.editData.collType : undefined,
|
||||
collateralNature: this.editData.collateralNature,
|
||||
isNineArea: this.editData.isNineArea,
|
||||
collThirdParty: this.isOne(this.editData.collThirdParty),
|
||||
couponRate: this.editData.couponRate
|
||||
}
|
||||
@@ -374,6 +449,8 @@ export default {
|
||||
isGreenLoan: false,
|
||||
isTradeBuildEnt: false,
|
||||
collType: undefined,
|
||||
collateralNature: undefined,
|
||||
isNineArea: undefined,
|
||||
collThirdParty: false,
|
||||
couponRate: undefined
|
||||
}
|
||||
@@ -393,14 +470,38 @@ export default {
|
||||
/** 清空抵质押字段 */
|
||||
resetCollateralFields() {
|
||||
this.form.collType = undefined
|
||||
this.form.collateralNature = undefined
|
||||
this.form.isNineArea = undefined
|
||||
this.form.collThirdParty = false
|
||||
this.resetCouponRateIfNotCertificatePledge()
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.form) {
|
||||
this.$refs.form.clearValidate(['collType', 'collThirdParty', 'couponRate'])
|
||||
this.$refs.form.clearValidate(['collType', 'collateralNature', 'isNineArea', 'collThirdParty', 'couponRate'])
|
||||
}
|
||||
})
|
||||
},
|
||||
handleCollateralNatureChange() {
|
||||
this.form.isNineArea = undefined
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.form) {
|
||||
this.$refs.form.clearValidate(['isNineArea'])
|
||||
}
|
||||
})
|
||||
},
|
||||
resolveMortgageCollateralType() {
|
||||
if (this.form.collateralNature === '普通住宅、土地、厂房') {
|
||||
return this.form.isNineArea === '是' ? '一类' : '二类'
|
||||
}
|
||||
if (this.form.collateralNature === '商业性质不动产') {
|
||||
return this.form.isNineArea === '是' ? '二类' : '三类'
|
||||
}
|
||||
if (this.form.collateralNature === '排污权') {
|
||||
return '排污权抵押'
|
||||
}
|
||||
if (this.form.collateralNature === '其他不动产') {
|
||||
return '其他不动产抵押'
|
||||
}
|
||||
},
|
||||
resetCouponRateIfNotCertificatePledge() {
|
||||
if (!this.isCertificatePledge) {
|
||||
this.form.couponRate = undefined
|
||||
@@ -472,6 +573,12 @@ export default {
|
||||
isGreenLoan: this.form.isGreenLoan ? '1' : '0',
|
||||
isTradeBuildEnt: this.form.isTradeBuildEnt ? '1' : '0'
|
||||
}
|
||||
if (this.isMortgage) {
|
||||
data.collType = this.resolveMortgageCollateralType()
|
||||
} else {
|
||||
delete data.collateralNature
|
||||
delete data.isNineArea
|
||||
}
|
||||
if (this.isCollateralGuarantee) {
|
||||
data.collThirdParty = this.form.collThirdParty ? '1' : '0'
|
||||
} else {
|
||||
@@ -512,6 +619,24 @@ export default {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.nine-area-control {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.nine-area-control .el-select {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.nine-area-help {
|
||||
flex: 0 0 auto;
|
||||
color: #909399;
|
||||
cursor: help;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.workflow-create-form .el-col {
|
||||
width: 100% !important;
|
||||
|
||||
@@ -13,14 +13,10 @@
|
||||
<el-descriptions-item label="客户名称">{{ detailData.custName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="客户类型">{{ detailData.custType }}</el-descriptions-item>
|
||||
<el-descriptions-item label="申请金额">{{ detailData.applyAmt }} 元</el-descriptions-item>
|
||||
<el-descriptions-item label="基准利率">
|
||||
<span class="rate-value">{{ getBaseLoanRate() }}</span> %
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="浮动BP">
|
||||
<span class="total-bp-value">{{ getTotalBp() }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="最终测算利率">
|
||||
<span class="calculate-rate">{{ getCalculateRate() }}</span> %
|
||||
<el-descriptions-item label="期限">{{ detailData.loanTerm || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="担保方式">{{ detailData.guarType || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="产品最低利率下限">
|
||||
<span class="rate-value">{{ formatRate(corpOutput && corpOutput.minRateProduct) }}</span> %
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="执行利率">
|
||||
<div class="execute-rate-input-wrapper">
|
||||
@@ -46,13 +42,6 @@
|
||||
|
||||
<!-- 右侧面板 -->
|
||||
<div class="right-panel">
|
||||
<!-- 模型输出卡片 -->
|
||||
<ModelOutputDisplay
|
||||
:cust-type="detailData.custType"
|
||||
:retail-output="null"
|
||||
:corp-output="corpOutput"
|
||||
/>
|
||||
|
||||
<!-- 流程详情卡片 -->
|
||||
<el-card class="detail-card">
|
||||
<div slot="header" class="card-header">
|
||||
@@ -64,11 +53,10 @@
|
||||
<h4 class="section-title">基本信息</h4>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="机构编码">{{ detailData.orgCode }}</el-descriptions-item>
|
||||
<el-descriptions-item label="运行模式">{{ detailData.runType }}</el-descriptions-item>
|
||||
<el-descriptions-item label="客户内码">{{ detailData.custIsn }}</el-descriptions-item>
|
||||
<el-descriptions-item label="客户名称">{{ detailData.custName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="证件类型">{{ detailData.idType }}</el-descriptions-item>
|
||||
<el-descriptions-item label="证件号码">{{ detailData.idNum }}</el-descriptions-item>
|
||||
<el-descriptions-item label="贷款期限">{{ detailData.loanTerm || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="创建时间">{{ detailData.createTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="创建者">{{ detailData.createBy }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
@@ -81,10 +69,17 @@
|
||||
<el-descriptions-item label="担保方式">{{ detailData.guarType }}</el-descriptions-item>
|
||||
<el-descriptions-item label="申请金额">{{ detailData.applyAmt }} 元</el-descriptions-item>
|
||||
<el-descriptions-item label="业务种类">{{ detailData.businessType || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="贷款期限">{{ detailData.loanTerm || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="历史贷款利率">{{ formatRate(detailData.loanRateHistory) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="余值覆盖">{{ formatBoolean(detailData.resCover) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="绿色贷款">{{ formatBoolean(detailData.isGreenLoan) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="贸易和建筑业企业">{{ formatBoolean(detailData.isTradeBuildEnt) }}</el-descriptions-item>
|
||||
<el-descriptions-item v-if="detailData.guarType === '抵押'" label="抵押物性质">
|
||||
{{ detailData.collateralNature || '-' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item v-if="detailData.guarType === '抵押'" label="是否属于九地">
|
||||
{{ detailData.isNineArea || '-' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="抵质押类型">{{ detailData.collType || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="抵质押物是否三方所有">{{
|
||||
formatBoolean(detailData.collThirdParty)
|
||||
@@ -94,6 +89,14 @@
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 模型输出卡片 -->
|
||||
<ModelOutputDisplay
|
||||
:cust-type="detailData.custType"
|
||||
:guar-type="detailData.guarType"
|
||||
:retail-output="null"
|
||||
:corp-output="corpOutput"
|
||||
/>
|
||||
|
||||
<!-- 议价池卡片 -->
|
||||
<BargainingPoolDisplay
|
||||
v-if="bargainingPool"
|
||||
@@ -155,18 +158,6 @@ export default {
|
||||
if (value === 'false' || value === false || value === '0' || value === 0) return '否'
|
||||
return value || '-'
|
||||
},
|
||||
/** 获取基准利率 */
|
||||
getBaseLoanRate() {
|
||||
return this.formatRate(this.corpOutput?.baseLoanRate)
|
||||
},
|
||||
/** 获取浮动BP */
|
||||
getTotalBp() {
|
||||
return this.corpOutput?.totalBp || '-'
|
||||
},
|
||||
/** 获取最终测算利率 */
|
||||
getCalculateRate() {
|
||||
return this.formatRate(this.corpOutput?.finalCalculateRate)
|
||||
},
|
||||
/** 设定执行利率 */
|
||||
handleSetExecuteRate() {
|
||||
const value = this.executeRateInput
|
||||
@@ -248,16 +239,6 @@ export default {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.total-bp-value {
|
||||
color: #e6a23c;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.calculate-rate {
|
||||
color: #f56c6c;
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
:close-on-click-modal="false" @close="handleClose">
|
||||
<el-form :model="queryForm" inline size="small">
|
||||
<el-form-item label="客户号">
|
||||
<el-input v-model="queryForm.custId" placeholder="请输入客户号" clearable @keyup.enter.native="handleQuery"/>
|
||||
<el-input v-model="queryForm.custId" placeholder="请输入客户号" clearable
|
||||
@keydown.enter.native.prevent="handleQuery"/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" :loading="loading" @click="handleQuery">查询</el-button>
|
||||
|
||||
@@ -6,203 +6,176 @@
|
||||
<div class="output-sections">
|
||||
<!-- 个人客户模型输出 -->
|
||||
<template v-if="custType === '个人' && retailOutput">
|
||||
<div class="output-section">
|
||||
<h4 class="section-title">基本信息</h4>
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="客户内码">{{ retailOutput.custIsn || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="客户名称">{{ retailOutput.custName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="证件类型">{{ retailOutput.idType || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="证件号码">{{ retailOutput.idNum || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="基准利率"><span class="rate-value">{{ formatRate(retailOutput.baseLoanRate) }}</span> %</el-descriptions-item>
|
||||
<el-descriptions-item label="灰黑名单客户">{{ formatOutputValue(retailOutput.greyBlackCust) }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
|
||||
<div class="output-section">
|
||||
<h4 class="section-title">测算结果</h4>
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions :column="3" border size="small">
|
||||
<el-descriptions-item label="基准利率"><span class="rate-value">{{ formatRate(retailOutput.baseLoanRate) }}</span> %</el-descriptions-item>
|
||||
<el-descriptions-item label="浮动BP"><span class="total-bp-value">{{ retailOutput.totalBp || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="测算利率"><span class="calculate-rate">{{ formatRate(retailOutput.calculateRate) }}</span> %</el-descriptions-item>
|
||||
<el-descriptions-item label="模型测算利率"><span class="calculate-rate">{{ formatRate(retailOutput.calculateRate) }}</span> %</el-descriptions-item>
|
||||
<el-descriptions-item label="历史利率">{{ formatRate(retailOutput.loanRateHistory) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="产品最低利率下限">{{ formatRate(retailOutput.minRateProduct) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="平滑幅度">{{ formatRate(retailOutput.smoothRange) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="平滑利率"><span class="calculate-rate">{{ formatRate(retailOutput.finalCalculateRate) }}</span> %</el-descriptions-item>
|
||||
<el-descriptions-item label="行社下调BP">{{ formatOutputValue(retailOutput.branchBp) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="参考利率"><span class="calculate-rate">{{ formatRate(retailOutput.referenceRate) }}</span> %</el-descriptions-item>
|
||||
<el-descriptions-item label="最终测算利率"><span class="calculate-rate">{{ formatRate(retailOutput.finalCalculateRate) }}</span> %</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
|
||||
<div class="output-section">
|
||||
<h4 class="section-title">忠诚度分析</h4>
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="我行首贷客户">{{ formatBoolean(retailOutput.isFirstLoan) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="用信天数">{{ retailOutput.faithDay || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="客户年龄">{{ retailOutput.custAge || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_首贷"><span class="bp-value">{{ retailOutput.bpFirstLoan || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="BP_贷龄"><span class="bp-value">{{ retailOutput.bpAgeLoan || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="BP_年龄"><span class="bp-value">{{ retailOutput.bpAge || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="TOTAL_BP_忠诚度" :span="2"><span class="total-bp-value">{{ retailOutput.totalBpLoyalty || '-' }}</span></el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<table class="output-analysis-table">
|
||||
<colgroup><col class="result-column"><col class="bp-column"></colgroup>
|
||||
<thead><tr><th>模型输出结果</th><th>影响BP</th></tr></thead>
|
||||
<tbody>
|
||||
<tr v-for="(row, index) in retailLoyaltyRows" :key="`retail-loyalty-${index}`" :class="{ 'is-total-row': row.total }">
|
||||
<td><span v-if="row.summary">汇总</span><div v-else v-for="item in row.results" :key="item.label" class="result-item"><span class="result-label">{{ item.label }}</span><span class="result-value">{{ item.value }}</span></div></td>
|
||||
<td><span :class="row.total ? 'total-bp-value' : 'bp-value'">{{ row.bpLabel }}:{{ row.bpValue }}</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="output-section">
|
||||
<h4 class="section-title">贡献度分析</h4>
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="存款年日均">{{ retailOutput.balanceAvg || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="贷款年日均">{{ retailOutput.loanAvg || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="派生率">{{ formatRate(retailOutput.derivationRate) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="TOTAL_BP_贡献度"><span class="total-bp-value">{{ retailOutput.totalBpContribution || '-' }}</span></el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<table class="output-analysis-table">
|
||||
<colgroup><col class="result-column"><col class="bp-column"></colgroup>
|
||||
<thead><tr><th>模型输出结果</th><th>影响BP</th></tr></thead>
|
||||
<tbody>
|
||||
<tr v-for="(row, index) in retailContributionRows" :key="`retail-contribution-${index}`" :class="{ 'is-total-row': row.total }">
|
||||
<td><span v-if="row.summary">汇总</span><div v-else v-for="item in row.results" :key="item.label" class="result-item"><span class="result-label">{{ item.label }}</span><span class="result-value">{{ item.value }}</span></div></td>
|
||||
<td>
|
||||
<span v-if="row.bpLabel" :class="row.total ? 'total-bp-value' : 'bp-value'">
|
||||
{{ row.bpLabel }}:{{ row.bpValue }}
|
||||
<el-tooltip v-if="row.bpTooltip" :content="row.bpTooltip" placement="top">
|
||||
<i class="el-icon-question analysis-help" tabindex="0" :aria-label="row.bpTooltipAriaLabel"></i>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="output-section">
|
||||
<h4 class="section-title">关联度分析</h4>
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="中间业务_个人_信用卡">{{ formatBoolean(retailOutput.midPerCard) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_个人_一码通">{{ formatBoolean(retailOutput.midPerPass) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_个人_丰收互联">{{ formatBoolean(retailOutput.midPerHarvest) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_个人_有效客户">{{ formatBoolean(retailOutput.midPerEffect) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_个人_快捷支付">{{ formatBoolean(retailOutput.midPerQuickPay) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_个人_电费代扣">{{ formatBoolean(retailOutput.midPerEleDdc) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_个人_水费代扣">{{ formatBoolean(retailOutput.midPerWaterDdc) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_个人_华数费代扣">{{ formatBoolean(retailOutput.midPerHuashuDdc) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_个人_煤气费代扣">{{ formatBoolean(retailOutput.MidPerGasDdc) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_个人_市民卡">{{ formatBoolean(retailOutput.midPerCitizencard) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_个人_理财业务">{{ formatBoolean(retailOutput.midPerFinMan) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_个人_etc">{{ formatBoolean(retailOutput.midPerEtc) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_中间业务"><span class="bp-value">{{ retailOutput.bpMid || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="TOTAL_BP_关联度"><span class="total-bp-value">{{ retailOutput.totalBpRelevance || '-' }}</span></el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
|
||||
<div class="output-section">
|
||||
<h4 class="section-title">贷款特征</h4>
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="申请金额">{{ retailOutput.applyAmt || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_贷款额度"><span class="bp-value">{{ retailOutput.bpLoanAmount || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="贷款用途">{{ formatLoanPurpose(retailOutput.loanPurpose) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="是否有经营佐证">{{ formatBoolean(retailOutput.bizProof) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_贷款用途"><span class="bp-value">{{ retailOutput.bpLoanUse || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="循环功能">{{ formatBoolean(retailOutput.loanLoop) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_循环功能"><span class="bp-value">{{ retailOutput.bpLoanLoop || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="抵质押类型">{{ retailOutput.collType || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="抵质押物三方所有">{{ formatBoolean(retailOutput.collThirdParty) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_抵押物"><span class="bp-value">{{ retailOutput.bpCollateral || '-' }}</span></el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<table class="output-analysis-table">
|
||||
<colgroup><col class="result-column"><col class="bp-column"></colgroup>
|
||||
<thead><tr><th>模型输出结果</th><th>影响BP</th></tr></thead>
|
||||
<tbody>
|
||||
<tr v-for="(row, index) in retailRelevanceRows" :key="`retail-relevance-${index}`" :class="{ 'is-total-row': row.total }">
|
||||
<td>
|
||||
<span v-if="row.summary">汇总</span>
|
||||
<div v-else v-for="item in row.results" :key="item.label" class="result-item">
|
||||
<span class="result-label">{{ item.label }}</span>
|
||||
<span v-if="item.showValue !== false" class="result-value">{{ item.value }}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span :class="row.total ? 'total-bp-value' : 'bp-value'">
|
||||
<template v-if="row.bpLabel">
|
||||
{{ row.bpLabel }}:
|
||||
</template>{{ row.bpValue }}
|
||||
<el-tooltip v-if="row.bpTooltip" :content="row.bpTooltip" placement="top">
|
||||
<i class="el-icon-question analysis-help" tabindex="0" :aria-label="row.bpTooltipAriaLabel"></i>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="output-section">
|
||||
<h4 class="section-title">风险度分析</h4>
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="灰名单客户">{{ formatBoolean(retailOutput.greyCust) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="本金逾期">{{ formatBoolean(retailOutput.prinOverdue) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="利息逾期">{{ formatBoolean(retailOutput.interestOverdue) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="信用卡逾期">{{ formatBoolean(retailOutput.cardOverdue) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_灰名单与逾期"><span class="bp-value">{{ retailOutput.bpGreyOverdue || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="TOTAL_BP_风险度"><span class="total-bp-value">{{ retailOutput.totalBpRisk || '-' }}</span></el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<table class="output-analysis-table">
|
||||
<colgroup><col class="result-column"><col class="bp-column"></colgroup>
|
||||
<thead><tr><th>模型输出结果</th><th>影响BP</th></tr></thead>
|
||||
<tbody>
|
||||
<tr v-for="(row, index) in retailRiskRows" :key="`retail-risk-${index}`" :class="{ 'is-total-row': row.total }">
|
||||
<td><span v-if="row.summary">汇总</span><div v-else v-for="item in row.results" :key="item.label" class="result-item"><span class="result-label">{{ item.label }}</span><span class="result-value">{{ item.value }}</span></div></td>
|
||||
<td><span :class="row.total ? 'total-bp-value' : 'bp-value'">{{ row.bpLabel }}:{{ row.bpValue }}</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<!-- 企业客户模型输出 -->
|
||||
<template v-else-if="custType === '企业' && corpOutput">
|
||||
<div class="output-section">
|
||||
<h4 class="section-title">基本信息</h4>
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="客户内码">{{ corpOutput.custIsn || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="客户名称">{{ corpOutput.custName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="证件类型">{{ corpOutput.idType || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="证件号码">{{ corpOutput.idNum || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="基准利率"><span class="rate-value">{{ formatRate(corpOutput.baseLoanRate) }}</span> %</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
|
||||
<div class="output-section">
|
||||
<h4 class="section-title">测算结果</h4>
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions :column="3" border size="small">
|
||||
<el-descriptions-item label="基准利率"><span class="rate-value">{{ formatRate(corpOutput.baseLoanRate) }}</span> %</el-descriptions-item>
|
||||
<el-descriptions-item label="浮动BP"><span class="total-bp-value">{{ corpOutput.totalBp || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="测算利率"><span class="calculate-rate">{{ formatRate(corpOutput.calculateRate) }}</span> %</el-descriptions-item>
|
||||
<el-descriptions-item label="模型测算利率"><span class="calculate-rate">{{ formatRate(corpOutput.calculateRate) }}</span> %</el-descriptions-item>
|
||||
<el-descriptions-item label="历史利率">{{ formatRate(corpOutput.loanRateHistory) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="产品最低利率下限">{{ formatRate(corpOutput.minRateProduct) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="平滑幅度">{{ formatRate(corpOutput.smoothRange) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="平滑利率"><span class="calculate-rate">{{ formatRate(corpOutput.finalCalculateRate) }}</span> %</el-descriptions-item>
|
||||
<el-descriptions-item label="行社下调BP">{{ formatOutputValue(corpOutput.branchBp) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="参考利率"><span class="calculate-rate">{{ formatRate(corpOutput.referenceRate) }}</span> %</el-descriptions-item>
|
||||
<el-descriptions-item label="最终测算利率"><span class="calculate-rate">{{ formatRate(corpOutput.finalCalculateRate) }}</span> %</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
|
||||
<div class="output-section">
|
||||
<h4 class="section-title">忠诚度分析</h4>
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="我行首贷客户">{{ formatBoolean(corpOutput.isFirstLoan) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="用信天数">{{ corpOutput.faithDay || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_首贷"><span class="bp-value">{{ corpOutput.bpFirstLoan || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="BP_贷龄"><span class="bp-value">{{ corpOutput.bpAgeLoan || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="TOTAL_BP_忠诚度" :span="2"><span class="total-bp-value">{{ corpOutput.totalBpLoyalty || '-' }}</span></el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<table class="output-analysis-table">
|
||||
<colgroup><col class="result-column"><col class="bp-column"></colgroup>
|
||||
<thead><tr><th>模型输出结果</th><th>影响BP</th></tr></thead>
|
||||
<tbody>
|
||||
<tr v-for="(row, index) in corporateLoyaltyRows" :key="`corporate-loyalty-${index}`" :class="{ 'is-total-row': row.total }">
|
||||
<td><span v-if="row.summary">汇总</span><div v-else v-for="item in row.results" :key="item.label" class="result-item"><span class="result-label">{{ item.label }}</span><span class="result-value">{{ item.value }}</span></div></td>
|
||||
<td><span :class="row.total ? 'total-bp-value' : 'bp-value'">{{ row.bpLabel }}:{{ row.bpValue }}</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="output-section">
|
||||
<h4 class="section-title">贡献度分析</h4>
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="存款年日均">{{ corpOutput.balanceAvg || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="贷款年日均">{{ corpOutput.loanAvg || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="派生率">{{ formatRate(corpOutput.derivationRate) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="TOTAL_BP_贡献度"><span class="total-bp-value">{{ corpOutput.totalBpContribution || '-' }}</span></el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<table class="output-analysis-table">
|
||||
<colgroup><col class="result-column"><col class="bp-column"></colgroup>
|
||||
<thead><tr><th>模型输出结果</th><th>影响BP</th></tr></thead>
|
||||
<tbody>
|
||||
<tr v-for="(row, index) in corporateContributionRows" :key="`corporate-contribution-${index}`" :class="{ 'is-total-row': row.total }">
|
||||
<td><span v-if="row.summary">汇总</span><div v-else v-for="item in row.results" :key="item.label" class="result-item"><span class="result-label">{{ item.label }}</span><span class="result-value">{{ item.value }}</span></div></td>
|
||||
<td><span v-if="row.bpLabel" :class="row.total ? 'total-bp-value' : 'bp-value'">{{ row.bpLabel }}:{{ row.bpValue }}</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="output-section">
|
||||
<h4 class="section-title">关联度分析</h4>
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="中间业务_企业_企业互联">{{ formatBoolean(corpOutput.midEntConnect) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_企业_有效价值客户">{{ formatBoolean(corpOutput.midEntEffect) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_企业_国际业务">{{ formatBoolean(corpOutput.midEntInter) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_企业_承兑">{{ formatBoolean(corpOutput.midEntAccept) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_企业_贴现">{{ formatBoolean(corpOutput.midEntDiscount) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_企业_电费代扣">{{ formatBoolean(corpOutput.midEntEleDdc) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_企业_水费代扣">{{ formatBoolean(corpOutput.midEntWaterDdc) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_中间业务"><span class="bp-value">{{ corpOutput.bpMid || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="代发工资户数">{{ corpOutput.payroll || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="存量贷款余额">{{ corpOutput.invLoanAmount || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_代发工资"><span class="bp-value">{{ corpOutput.bpPayroll || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="TOTAL_BP_关联度"><span class="total-bp-value">{{ corpOutput.totalBpRelevance || '-' }}</span></el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
|
||||
<div class="output-section">
|
||||
<h4 class="section-title">企业类别</h4>
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="净身企业">{{ formatBoolean(corpOutput.isCleanEnt) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="开立基本结算账户">{{ formatBoolean(corpOutput.hasSettleAcct) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="绿色贷款">{{ formatBoolean(corpOutput.isGreenLoan) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="科技型企业">{{ formatBoolean(corpOutput.isTechEnt) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="贸易和建筑业企业">{{ formatBoolean(corpOutput.isTradeBuildEnt) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_企业客户类别"><span class="bp-value">{{ corpOutput.bpEntType || '-' }}</span></el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
|
||||
<div class="output-section">
|
||||
<h4 class="section-title">贷款特征</h4>
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="借款期限">{{ corpOutput.loanTerm || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_贷款期限"><span class="bp-value">{{ corpOutput.bpLoanTerm || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="申请金额">{{ corpOutput.applyAmt || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_贷款额度"><span class="bp-value">{{ corpOutput.bpLoanAmount || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="抵质押类型">{{ corpOutput.collType || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="抵质押物三方所有">{{ formatBoolean(corpOutput.collThirdParty) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_抵押物"><span class="bp-value">{{ corpOutput.bpCollateral || '-' }}</span></el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<table class="output-analysis-table">
|
||||
<colgroup><col class="result-column"><col class="bp-column"></colgroup>
|
||||
<thead><tr><th>模型输出结果</th><th>影响BP</th></tr></thead>
|
||||
<tbody>
|
||||
<tr v-for="(row, index) in corporateRelevanceRows" :key="`corporate-relevance-${index}`" :class="{ 'is-total-row': row.total }">
|
||||
<td><span v-if="row.summary">汇总</span><template v-else><div v-if="row.category" class="result-category">{{ row.category }}</div><div v-for="item in row.results" :key="item.label" class="result-item"><span class="result-label">{{ item.label }}</span><span v-if="item.showValue !== false" class="result-value">{{ item.value }}</span></div></template></td>
|
||||
<td>
|
||||
<span :class="row.total ? 'total-bp-value' : 'bp-value'">
|
||||
<template v-if="row.bpLabel">{{ row.bpLabel }}:</template>{{ row.bpValue }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="output-section">
|
||||
<h4 class="section-title">风险度分析</h4>
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="灰名单客户">{{ formatBoolean(corpOutput.greyCust) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="本金逾期">{{ formatBoolean(corpOutput.prinOverdue) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="利息逾期">{{ formatBoolean(corpOutput.interestOverdue) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_灰名单与逾期"><span class="bp-value">{{ corpOutput.bpGreyOverdue || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="TOTAL_BP_风险度"><span class="total-bp-value">{{ corpOutput.totalBpRisk || '-' }}</span></el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<table class="output-analysis-table">
|
||||
<colgroup><col class="result-column"><col class="bp-column"></colgroup>
|
||||
<thead><tr><th>模型输出结果</th><th>影响BP</th></tr></thead>
|
||||
<tbody>
|
||||
<tr v-for="(row, index) in corporateRiskRows" :key="`corporate-risk-${index}`" :class="{ 'is-total-row': row.total }">
|
||||
<td><span v-if="row.summary">汇总</span><div v-else v-for="item in row.results" :key="item.label" class="result-item"><span class="result-label">{{ item.label }}</span><span class="result-value">{{ item.value }}</span></div></td>
|
||||
<td><span :class="row.total ? 'total-bp-value' : 'bp-value'">{{ row.bpLabel }}:{{ row.bpValue }}</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
</div>
|
||||
</el-card>
|
||||
@@ -225,10 +198,156 @@ export default {
|
||||
corpOutput: {
|
||||
type: Object,
|
||||
default: null
|
||||
},
|
||||
guarType: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
retailLoyaltyRows() {
|
||||
return [
|
||||
this.analysisRow('我行首贷客户', this.formatBoolean(this.retailOutput.isFirstLoan), 'BP_首贷', this.retailOutput.bpFirstLoan),
|
||||
this.analysisRow('用信天数', this.retailOutput.faithDay, 'BP_贷龄', this.retailOutput.bpAgeLoan),
|
||||
this.analysisRow('客户年龄', this.retailOutput.custAge, 'BP_年龄', this.retailOutput.bpAge),
|
||||
this.totalRow('TOTAL_BP_忠诚度', this.retailOutput.totalBpLoyalty)
|
||||
]
|
||||
},
|
||||
retailContributionRows() {
|
||||
return [
|
||||
this.groupedAnalysisRow([
|
||||
this.resultItem('存款年日均', this.retailOutput.balanceAvg),
|
||||
this.resultItem('贷款年日均', this.retailOutput.loanAvg),
|
||||
this.resultItem('派生率', this.formatRate(this.retailOutput.derivationRate))
|
||||
]),
|
||||
this.totalRow('TOTAL_BP_贡献度', this.retailOutput.totalBpContribution, '最高上限100BP', '查看贡献度汇总上限')
|
||||
]
|
||||
},
|
||||
retailRelevanceRows() {
|
||||
return [
|
||||
this.middleBusinessRow('中间业务_个人_信用卡', this.retailOutput.midPerCard, '办理减5个BP,信用卡额度1万元及以上的再减10个BP'),
|
||||
this.middleBusinessRow('中间业务_个人_一码通', this.retailOutput.midPerPass),
|
||||
this.middleBusinessRow('中间业务_个人_丰收互联', this.retailOutput.midPerHarvest),
|
||||
this.middleBusinessRow('中间业务_个人_有效客户', this.retailOutput.midPerEffect),
|
||||
this.middleBusinessRow('中间业务_个人_快捷支付', this.retailOutput.midPerQuickPay),
|
||||
this.middleBusinessRow('中间业务_个人_电费代扣', this.retailOutput.midPerEleDdc),
|
||||
this.middleBusinessRow('中间业务_个人_水费代扣', this.retailOutput.midPerWaterDdc),
|
||||
this.middleBusinessRow('中间业务_个人_华数费代扣', this.retailOutput.midPerHuashuDdc),
|
||||
this.middleBusinessRow('中间业务_个人_煤气费代扣', this.retailOutput.midPerGasDdc),
|
||||
this.middleBusinessRow('中间业务_个人_市民卡', this.retailOutput.midPerCitizencard),
|
||||
this.middleBusinessRow('中间业务_个人_理财业务', this.retailOutput.midPerFinMan),
|
||||
this.middleBusinessRow('中间业务_个人_etc', this.retailOutput.midPerEtc),
|
||||
this.totalRow('TOTAL_BP_关联度', this.retailOutput.totalBpRelevance, '最高上限-30BP', '查看中间业务BP上限')
|
||||
]
|
||||
},
|
||||
retailRiskRows() {
|
||||
const rows = [
|
||||
this.analysisRow('申请金额', this.retailOutput.applyAmt, 'BP_贷款额度', this.retailOutput.bpLoanAmount),
|
||||
this.groupedAnalysisRow([
|
||||
this.resultItem('贷款用途', this.formatLoanPurpose(this.retailOutput.loanPurpose)),
|
||||
this.resultItem('营业执照', this.formatBoolean(this.retailOutput.bizProof))
|
||||
], 'BP_贷款用途', this.retailOutput.bpLoanUse),
|
||||
this.analysisRow('循环功能', this.formatBoolean(this.retailOutput.loanLoop), 'BP_循环功能', this.retailOutput.bpLoanLoop)
|
||||
]
|
||||
if (this.guarType === '抵押' || this.guarType === '质押') {
|
||||
rows.push(this.analysisRow('抵押物第三方所有', this.formatBoolean(this.retailOutput.collThirdParty), 'BP_抵押物', this.retailOutput.bpCollateral))
|
||||
}
|
||||
rows.push(
|
||||
this.analysisRow('本金逾期', this.formatBoolean(this.retailOutput.prinOverdue), 'BP_本金逾期', this.retailOutput.bpPrinOverdue),
|
||||
this.analysisRow('利息逾期', this.formatBoolean(this.retailOutput.interestOverdue), 'BP_利息逾期', this.retailOutput.bpIinterestOverdue),
|
||||
this.analysisRow('信用卡逾期', this.formatBoolean(this.retailOutput.cardOverdue), 'BP_信用卡逾期', this.retailOutput.bpCardOverdue),
|
||||
this.totalRow('TOTAL_BP_风险度', this.retailOutput.totalBpRisk)
|
||||
)
|
||||
return rows
|
||||
},
|
||||
corporateLoyaltyRows() {
|
||||
return [
|
||||
this.analysisRow('我行首贷客户', this.formatBoolean(this.corpOutput.isFirstLoan), 'BP_首贷', this.corpOutput.bpFirstLoan),
|
||||
this.analysisRow('用信天数', this.corpOutput.faithDay, 'BP_贷龄', this.corpOutput.bpAgeLoan),
|
||||
this.totalRow('TOTAL_BP_忠诚度', this.corpOutput.totalBpLoyalty)
|
||||
]
|
||||
},
|
||||
corporateContributionRows() {
|
||||
return [
|
||||
this.groupedAnalysisRow([
|
||||
this.resultItem('存款年日均', this.corpOutput.balanceAvg),
|
||||
this.resultItem('贷款年日均', this.corpOutput.loanAvg),
|
||||
this.resultItem('派生率', this.formatRate(this.corpOutput.derivationRate))
|
||||
]),
|
||||
this.totalRow('TOTAL_BP_贡献度', this.corpOutput.totalBpContribution)
|
||||
]
|
||||
},
|
||||
corporateRelevanceRows() {
|
||||
return [
|
||||
this.middleBusinessRow('中间业务_企业_企业互联', this.corpOutput.midEntConnect),
|
||||
this.middleBusinessRow('中间业务_企业_有效价值客户', this.corpOutput.midEntEffect),
|
||||
this.middleBusinessRow('中间业务_企业_国际业务', this.corpOutput.midEntInter),
|
||||
this.middleBusinessRow('中间业务_企业_承兑', this.corpOutput.midEntAccept),
|
||||
this.middleBusinessRow('中间业务_企业_贴现', this.corpOutput.midEntDiscount),
|
||||
this.middleBusinessRow('中间业务_企业_电费代扣', this.corpOutput.midEntEleDdc),
|
||||
this.middleBusinessRow('中间业务_企业_水费代扣', this.corpOutput.midEntWaterDdc),
|
||||
this.groupedAnalysisRow([
|
||||
this.resultItem('代发工资户数', this.corpOutput.payroll),
|
||||
this.resultItem('存量贷款余额', this.corpOutput.invLoanAmount)
|
||||
], 'BP_代发工资', this.corpOutput.bpPayroll, false, '代发工资'),
|
||||
this.groupedAnalysisRow([
|
||||
this.resultItem('净身企业', this.formatBoolean(this.corpOutput.isCleanEnt)),
|
||||
this.resultItem('开立基本结算账户', this.formatBoolean(this.corpOutput.hasSettleAcct)),
|
||||
this.resultItem('绿色贷款', this.formatBoolean(this.corpOutput.isGreenLoan)),
|
||||
this.resultItem('科技型企业', this.formatBoolean(this.corpOutput.isTechEnt)),
|
||||
this.resultItem('贸易和建筑业企业', this.formatBoolean(this.corpOutput.isTradeBuildEnt))
|
||||
], 'BP_企业客户类别', this.corpOutput.bpEntType, false, '客户类型'),
|
||||
this.totalRow('TOTAL_BP_关联度', this.corpOutput.totalBpRelevance)
|
||||
]
|
||||
},
|
||||
corporateRiskRows() {
|
||||
const rows = [
|
||||
this.analysisRow('借款期限', this.corpOutput.loanTerm, 'BP_贷款期限', this.corpOutput.bpLoanTerm),
|
||||
this.analysisRow('申请金额', this.corpOutput.applyAmt, 'BP_贷款额度', this.corpOutput.bpLoanAmount)
|
||||
]
|
||||
if (this.guarType === '抵押' || this.guarType === '质押') {
|
||||
rows.push(this.groupedAnalysisRow([
|
||||
this.resultItem('抵质押类型', this.corpOutput.collType),
|
||||
this.resultItem('抵质押物三方所有', this.formatBoolean(this.corpOutput.collThirdParty))
|
||||
], 'BP_抵押物', this.corpOutput.bpCollateral))
|
||||
}
|
||||
rows.push(
|
||||
this.groupedAnalysisRow([
|
||||
this.resultItem('灰名单客户', this.formatBoolean(this.corpOutput.greyCust)),
|
||||
this.resultItem('黑名单客户', this.formatBoolean(this.corpOutput.blackCust))
|
||||
], 'BP_灰名单与逾期', this.corpOutput.bpGreyOverdue),
|
||||
this.analysisRow('本金逾期', this.formatBoolean(this.corpOutput.prinOverdue), 'BP_本金逾期', this.corpOutput.bpPrinOverdue),
|
||||
this.analysisRow('利息逾期', this.corpOutput.interestOverdue, 'BP_利息逾期', this.corpOutput.bpIinterestOverdue),
|
||||
this.analysisRow('信用卡逾期', this.formatBoolean(this.corpOutput.cardOverdue), 'BP_信用卡逾期', this.corpOutput.bpCardOverdue),
|
||||
this.totalRow('TOTAL_BP_风险度', this.corpOutput.totalBpRisk)
|
||||
)
|
||||
return rows
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
formatRate,
|
||||
resultItem(label, value, showValue = true) {
|
||||
return {label, value: this.formatOutputValue(value), showValue}
|
||||
},
|
||||
groupedAnalysisRow(results, bpLabel, bpValue, total = false, category = null) {
|
||||
return {results, bpLabel, bpValue: this.formatOutputValue(bpValue), total, category}
|
||||
},
|
||||
analysisRow(resultLabel, resultValue, bpLabel, bpValue) {
|
||||
return this.groupedAnalysisRow([this.resultItem(resultLabel, resultValue)], bpLabel, bpValue)
|
||||
},
|
||||
middleBusinessRow(resultLabel, bpValue, tooltip = null) {
|
||||
return {
|
||||
results: [this.resultItem(resultLabel, null, false)],
|
||||
bpLabel: null,
|
||||
bpValue: this.formatOutputValue(bpValue),
|
||||
total: false,
|
||||
bpTooltip: tooltip,
|
||||
bpTooltipAriaLabel: tooltip ? `${resultLabel}提示` : null
|
||||
}
|
||||
},
|
||||
totalRow(bpLabel, bpValue, bpTooltip = null, bpTooltipAriaLabel = null) {
|
||||
return {summary: true, bpLabel, bpValue: this.formatOutputValue(bpValue), total: true, bpTooltip, bpTooltipAriaLabel}
|
||||
},
|
||||
/** 格式化布尔值为中文 */
|
||||
formatBoolean(value) {
|
||||
if (value === 'true' || value === true || value === '1' || value === 1) return '是'
|
||||
@@ -283,6 +402,98 @@ export default {
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.analysis-help {
|
||||
margin-left: 4px;
|
||||
color: #909399;
|
||||
cursor: help;
|
||||
font-size: 14px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.output-analysis-table {
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
border-collapse: collapse;
|
||||
border: 1px solid #ebeef5;
|
||||
color: #606266;
|
||||
font-size: 13px;
|
||||
|
||||
.result-column {
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
.bp-column {
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: 10px 12px;
|
||||
border-right: 1px solid #ebeef5;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
overflow-wrap: anywhere;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
th:last-child,
|
||||
td:last-child {
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
tbody tr:last-child td {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
th {
|
||||
background: #f5f7fa;
|
||||
color: #909399;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.result-item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px 12px;
|
||||
}
|
||||
|
||||
.result-item + .result-item {
|
||||
margin-top: 6px;
|
||||
padding-top: 6px;
|
||||
border-top: 1px dashed #ebeef5;
|
||||
}
|
||||
|
||||
.result-category {
|
||||
margin-bottom: 8px;
|
||||
color: #303133;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.result-label {
|
||||
min-width: 0;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.result-value {
|
||||
margin-left: auto;
|
||||
color: #303133;
|
||||
font-weight: 500;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.is-total-row {
|
||||
background: #fffaf0;
|
||||
|
||||
td:first-child {
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// BP 值样式
|
||||
.bp-value {
|
||||
color: #409eff;
|
||||
@@ -308,4 +519,44 @@ export default {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.model-output-card {
|
||||
::v-deep .el-card__body {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.output-analysis-table {
|
||||
th,
|
||||
td {
|
||||
padding: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media print {
|
||||
.model-output-card {
|
||||
break-inside: auto !important;
|
||||
page-break-inside: auto !important;
|
||||
|
||||
.output-section {
|
||||
break-inside: auto;
|
||||
page-break-inside: auto;
|
||||
}
|
||||
|
||||
.output-analysis-table {
|
||||
color: #000;
|
||||
|
||||
thead {
|
||||
display: table-header-group;
|
||||
}
|
||||
|
||||
tr {
|
||||
break-inside: avoid !important;
|
||||
page-break-inside: avoid !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -52,6 +52,14 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="贷款用途" prop="loanPurpose">
|
||||
<el-select v-model="form.loanPurpose" placeholder="请选择贷款用途" style="width: 100%">
|
||||
<el-option label="经营" value="business"/>
|
||||
<el-option label="消费" value="consumer"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="借款期限(年)" prop="loanTerm">
|
||||
<el-select v-model="form.loanTerm" placeholder="请选择借款期限" style="width: 100%">
|
||||
@@ -77,6 +85,11 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="是否有营业执照" prop="bizProof">
|
||||
<el-switch v-model="form.bizProof"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="循环功能" prop="loanLoop">
|
||||
<el-switch v-model="form.loanLoop"/>
|
||||
@@ -87,7 +100,33 @@
|
||||
<!-- 抵质押信息 -->
|
||||
<el-divider v-if="isCollateralGuarantee" content-position="left">抵质押信息</el-divider>
|
||||
<el-row v-if="isCollateralGuarantee">
|
||||
<el-col :span="12">
|
||||
<template v-if="isMortgage">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="抵押物性质" prop="collateralNature">
|
||||
<el-select v-model="form.collateralNature" placeholder="请选择抵押物性质" style="width: 100%">
|
||||
<el-option v-for="item in collateralNatureOptions" :key="item" :label="item" :value="item"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="是否属于九地" prop="isNineArea">
|
||||
<div class="nine-area-control">
|
||||
<el-select
|
||||
v-model="form.isNineArea"
|
||||
:disabled="!requiresNineArea"
|
||||
:placeholder="requiresNineArea ? '请选择是否属于九地' : '无需选择'"
|
||||
>
|
||||
<el-option label="是" value="是"/>
|
||||
<el-option label="否" value="否"/>
|
||||
</el-select>
|
||||
<el-tooltip content="九地是指绍兴、杭州、宁波、上海、北京、广州、深圳、南京、苏州" placement="top">
|
||||
<i class="el-icon-question nine-area-help" tabindex="0" aria-label="查看九地说明"></i>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</template>
|
||||
<el-col :span="12" v-if="isPledge">
|
||||
<el-form-item label="抵质押类型" prop="collType">
|
||||
<el-select v-model="form.collType" placeholder="请选择抵质押类型" style="width: 100%">
|
||||
<el-option v-for="item in collateralTypeOptions" :key="item" :label="item" :value="item"/>
|
||||
@@ -168,6 +207,30 @@ export default {
|
||||
callback()
|
||||
}
|
||||
|
||||
const validateCollateralType = (rule, value, callback) => {
|
||||
if (this.isPledge && !value) {
|
||||
callback(new Error('请选择抵质押类型'))
|
||||
return
|
||||
}
|
||||
callback()
|
||||
}
|
||||
|
||||
const validateCollateralNature = (rule, value, callback) => {
|
||||
if (this.isMortgage && !value) {
|
||||
callback(new Error('请选择抵押物性质'))
|
||||
return
|
||||
}
|
||||
callback()
|
||||
}
|
||||
|
||||
const validateNineArea = (rule, value, callback) => {
|
||||
if (this.requiresNineArea && !value) {
|
||||
callback(new Error('请选择是否属于九地'))
|
||||
return
|
||||
}
|
||||
callback()
|
||||
}
|
||||
|
||||
return {
|
||||
loanTermOptions: [
|
||||
'1', '2', '3', '4', '5', '6'
|
||||
@@ -187,11 +250,15 @@ export default {
|
||||
idNum: this.customerMap ? (this.customerMap.cust_id || '').substring(3) : undefined,
|
||||
guarType: undefined,
|
||||
applyAmt: undefined,
|
||||
loanPurpose: undefined,
|
||||
loanTerm: undefined,
|
||||
businessType: undefined,
|
||||
loanRateHistory: undefined,
|
||||
bizProof: false,
|
||||
loanLoop: false,
|
||||
collType: undefined,
|
||||
collateralNature: undefined,
|
||||
isNineArea: undefined,
|
||||
collThirdParty: false,
|
||||
couponRate: undefined
|
||||
},
|
||||
@@ -216,6 +283,9 @@ export default {
|
||||
applyAmt: [
|
||||
{required: true, validator: validateApplyAmt, trigger: "blur"}
|
||||
],
|
||||
loanPurpose: [
|
||||
{required: true, message: "请选择贷款用途", trigger: "change"}
|
||||
],
|
||||
loanTerm: [
|
||||
{required: true, message: "请选择借款期限", trigger: "change"}
|
||||
],
|
||||
@@ -226,7 +296,13 @@ export default {
|
||||
{required: true, message: "请选择历史贷款合同", trigger: "change"}
|
||||
],
|
||||
collType: [
|
||||
{required: true, message: "请选择抵质押类型", trigger: "change"}
|
||||
{validator: validateCollateralType, trigger: "change"}
|
||||
],
|
||||
collateralNature: [
|
||||
{validator: validateCollateralNature, trigger: "change"}
|
||||
],
|
||||
isNineArea: [
|
||||
{validator: validateNineArea, trigger: "change"}
|
||||
],
|
||||
couponRate: [
|
||||
{validator: validateCouponRate, trigger: "blur"}
|
||||
@@ -246,6 +322,15 @@ export default {
|
||||
isCollateralGuarantee() {
|
||||
return this.form.guarType === '抵押' || this.form.guarType === '质押'
|
||||
},
|
||||
isMortgage() {
|
||||
return this.form.guarType === '抵押'
|
||||
},
|
||||
isPledge() {
|
||||
return this.form.guarType === '质押'
|
||||
},
|
||||
requiresNineArea() {
|
||||
return this.isMortgage && ['普通住宅、土地、厂房', '商业性质不动产'].includes(this.form.collateralNature)
|
||||
},
|
||||
isStockTransfer() {
|
||||
return this.form.businessType === '存量转贷'
|
||||
},
|
||||
@@ -259,13 +344,13 @@ export default {
|
||||
return this.isEdit ? '编辑个人利率定价流程' : '新增个人利率定价流程'
|
||||
},
|
||||
collateralTypeOptions() {
|
||||
if (this.form.guarType === '抵押') {
|
||||
return ['一线', '一类', '二类', '三类']
|
||||
}
|
||||
if (this.form.guarType === '质押') {
|
||||
if (this.isPledge) {
|
||||
return ['存单质押', '其他质押']
|
||||
}
|
||||
return []
|
||||
},
|
||||
collateralNatureOptions() {
|
||||
return ['普通住宅、土地、厂房', '商业性质不动产', '其他抵押财产']
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -287,6 +372,12 @@ export default {
|
||||
return
|
||||
}
|
||||
this.resetCouponRateIfNotCertificatePledge()
|
||||
},
|
||||
'form.collateralNature'(val, oldVal) {
|
||||
if (this.resettingForm || val === oldVal) {
|
||||
return
|
||||
}
|
||||
this.handleCollateralNatureChange()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -318,11 +409,15 @@ export default {
|
||||
idNum: this.editData.idNum,
|
||||
guarType: this.editData.guarType,
|
||||
applyAmt: this.editData.applyAmt,
|
||||
loanPurpose: this.editData.loanPurpose,
|
||||
loanTerm: this.editData.loanTerm,
|
||||
businessType: this.editData.businessType,
|
||||
loanRateHistory: this.editData.loanRateHistory,
|
||||
bizProof: this.isOne(this.editData.bizProof),
|
||||
loanLoop: this.isOne(this.editData.loanLoop),
|
||||
collType: this.editData.collType,
|
||||
collType: this.editData.guarType === '质押' ? this.editData.collType : undefined,
|
||||
collateralNature: this.editData.collateralNature,
|
||||
isNineArea: this.editData.isNineArea,
|
||||
collThirdParty: this.isOne(this.editData.collThirdParty),
|
||||
couponRate: this.editData.couponRate
|
||||
}
|
||||
@@ -336,11 +431,15 @@ export default {
|
||||
idNum: this.customerMap ? (this.customerMap.cust_id || '').substring(3) : undefined,
|
||||
guarType: undefined,
|
||||
applyAmt: undefined,
|
||||
loanPurpose: undefined,
|
||||
loanTerm: undefined,
|
||||
businessType: undefined,
|
||||
loanRateHistory: undefined,
|
||||
bizProof: false,
|
||||
loanLoop: false,
|
||||
collType: undefined,
|
||||
collateralNature: undefined,
|
||||
isNineArea: undefined,
|
||||
collThirdParty: false,
|
||||
couponRate: undefined
|
||||
}
|
||||
@@ -360,14 +459,35 @@ export default {
|
||||
/** 清空抵质押字段 */
|
||||
resetCollateralFields() {
|
||||
this.form.collType = undefined
|
||||
this.form.collateralNature = undefined
|
||||
this.form.isNineArea = undefined
|
||||
this.form.collThirdParty = false
|
||||
this.resetCouponRateIfNotCertificatePledge()
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.form) {
|
||||
this.$refs.form.clearValidate(['collType', 'collThirdParty', 'couponRate'])
|
||||
this.$refs.form.clearValidate(['collType', 'collateralNature', 'isNineArea', 'collThirdParty', 'couponRate'])
|
||||
}
|
||||
})
|
||||
},
|
||||
handleCollateralNatureChange() {
|
||||
this.form.isNineArea = undefined
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.form) {
|
||||
this.$refs.form.clearValidate(['isNineArea'])
|
||||
}
|
||||
})
|
||||
},
|
||||
resolveMortgageCollateralType() {
|
||||
if (this.form.collateralNature === '普通住宅、土地、厂房') {
|
||||
return this.form.isNineArea === '是' ? '一类' : '二类'
|
||||
}
|
||||
if (this.form.collateralNature === '商业性质不动产') {
|
||||
return this.form.isNineArea === '是' ? '二类' : '三类'
|
||||
}
|
||||
if (this.form.collateralNature === '其他抵押财产') {
|
||||
return '四类'
|
||||
}
|
||||
},
|
||||
resetCouponRateIfNotCertificatePledge() {
|
||||
if (!this.isCertificatePledge) {
|
||||
this.form.couponRate = undefined
|
||||
@@ -435,8 +555,15 @@ export default {
|
||||
// 转换开关值为字符串
|
||||
const data = {
|
||||
...this.form,
|
||||
bizProof: this.form.bizProof ? '1' : '0',
|
||||
loanLoop: this.form.loanLoop ? '1' : '0'
|
||||
}
|
||||
if (this.isMortgage) {
|
||||
data.collType = this.resolveMortgageCollateralType()
|
||||
} else {
|
||||
delete data.collateralNature
|
||||
delete data.isNineArea
|
||||
}
|
||||
if (this.isCollateralGuarantee) {
|
||||
data.collThirdParty = this.form.collThirdParty ? '1' : '0'
|
||||
} else {
|
||||
@@ -477,6 +604,24 @@ export default {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.nine-area-control {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.nine-area-control .el-select {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.nine-area-help {
|
||||
flex: 0 0 auto;
|
||||
color: #909399;
|
||||
cursor: help;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.workflow-create-form .el-col {
|
||||
width: 100% !important;
|
||||
|
||||
@@ -13,14 +13,10 @@
|
||||
<el-descriptions-item label="客户名称">{{ detailData.custName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="客户类型">{{ detailData.custType }}</el-descriptions-item>
|
||||
<el-descriptions-item label="申请金额">{{ detailData.applyAmt }} 元</el-descriptions-item>
|
||||
<el-descriptions-item label="基准利率">
|
||||
<span class="rate-value">{{ getBaseLoanRate() }}</span> %
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="浮动BP">
|
||||
<span class="total-bp-value">{{ getTotalBp() }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="最终测算利率">
|
||||
<span class="calculate-rate">{{ getCalculateRate() }}</span> %
|
||||
<el-descriptions-item label="期限">{{ detailData.loanTerm || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="担保方式">{{ detailData.guarType || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="产品最低利率下限">
|
||||
<span class="rate-value">{{ formatRate(retailOutput && retailOutput.minRateProduct) }}</span> %
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="执行利率">
|
||||
<div class="execute-rate-input-wrapper">
|
||||
@@ -46,13 +42,6 @@
|
||||
|
||||
<!-- 右侧面板 -->
|
||||
<div class="right-panel">
|
||||
<!-- 模型输出卡片 -->
|
||||
<ModelOutputDisplay
|
||||
:cust-type="detailData.custType"
|
||||
:retail-output="retailOutput"
|
||||
:corp-output="null"
|
||||
/>
|
||||
|
||||
<!-- 流程详情卡片 -->
|
||||
<el-card class="detail-card">
|
||||
<div slot="header" class="card-header">
|
||||
@@ -64,10 +53,18 @@
|
||||
<h4 class="section-title">基本信息</h4>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="机构编码">{{ detailData.orgCode }}</el-descriptions-item>
|
||||
<el-descriptions-item label="运行模式">{{ detailData.runType }}</el-descriptions-item>
|
||||
<el-descriptions-item label="客户内码">{{ detailData.custIsn }}</el-descriptions-item>
|
||||
<el-descriptions-item label="客户名称">{{ detailData.custName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="证件类型">{{ detailData.idType }}</el-descriptions-item>
|
||||
<el-descriptions-item label="证件号码">{{ detailData.idNum }}</el-descriptions-item>
|
||||
<el-descriptions-item label="灰名单客户">{{
|
||||
formatBoolean(retailOutput && retailOutput.greyCust)
|
||||
}}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="黑名单客户">{{
|
||||
formatBoolean(retailOutput && retailOutput.blackCust)
|
||||
}}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="创建时间">{{ detailData.createTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="创建者">{{ detailData.createBy }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
@@ -83,11 +80,17 @@
|
||||
<el-descriptions-item label="业务种类">{{ detailData.businessType || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="历史贷款利率">{{ formatRate(detailData.loanRateHistory) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="借款期限">{{ detailData.loanTerm || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="是否有经营佐证">{{
|
||||
<el-descriptions-item label="是否有营业执照">{{
|
||||
formatBoolean(detailData.bizProof)
|
||||
}}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="循环功能">{{ formatBoolean(detailData.loanLoop) }}</el-descriptions-item>
|
||||
<el-descriptions-item v-if="detailData.guarType === '抵押'" label="抵押物性质">
|
||||
{{ detailData.collateralNature || '-' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item v-if="detailData.guarType === '抵押'" label="是否属于九地">
|
||||
{{ detailData.isNineArea || '-' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="抵质押类型">{{ detailData.collType || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="抵质押物是否三方所有">{{
|
||||
formatBoolean(detailData.collThirdParty)
|
||||
@@ -97,6 +100,14 @@
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 模型输出卡片 -->
|
||||
<ModelOutputDisplay
|
||||
:cust-type="detailData.custType"
|
||||
:guar-type="detailData.guarType"
|
||||
:retail-output="retailOutput"
|
||||
:corp-output="null"
|
||||
/>
|
||||
|
||||
<!-- 议价池卡片 -->
|
||||
<BargainingPoolDisplay
|
||||
v-if="bargainingPool"
|
||||
@@ -164,18 +175,6 @@ export default {
|
||||
if (value === 'business') return '经营'
|
||||
return value || '-'
|
||||
},
|
||||
/** 获取基准利率 */
|
||||
getBaseLoanRate() {
|
||||
return this.formatRate(this.retailOutput?.baseLoanRate)
|
||||
},
|
||||
/** 获取浮动BP */
|
||||
getTotalBp() {
|
||||
return this.retailOutput?.totalBp || '-'
|
||||
},
|
||||
/** 获取最终测算利率 */
|
||||
getCalculateRate() {
|
||||
return this.formatRate(this.retailOutput?.finalCalculateRate)
|
||||
},
|
||||
/** 设定执行利率 */
|
||||
handleSetExecuteRate() {
|
||||
const value = this.executeRateInput
|
||||
@@ -257,16 +256,6 @@ export default {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.total-bp-value {
|
||||
color: #e6a23c;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.calculate-rate {
|
||||
color: #f56c6c;
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,29 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form
|
||||
:model="queryParams"
|
||||
ref="queryForm"
|
||||
size="small"
|
||||
:inline="true"
|
||||
v-show="showSearch"
|
||||
label-width="68px"
|
||||
@submit.native.prevent="handleQuery"
|
||||
>
|
||||
<el-form-item label="客户信息" prop="custIsn">
|
||||
<el-input
|
||||
v-model="queryParams.custIsn"
|
||||
placeholder="请输入客户内码/证件号/客户名"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
@keydown.enter.native.prevent="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="客户类型" prop="custType">
|
||||
<el-form-item v-if="showAllSearchItems" label="客户类型" prop="custType">
|
||||
<el-select v-model="queryParams.custType" placeholder="请选择客户类型" clearable style="width: 160px">
|
||||
<el-option label="个人" value="个人" />
|
||||
<el-option label="企业" value="企业" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="担保方式" prop="guarType">
|
||||
<el-form-item v-if="showAllSearchItems" label="担保方式" prop="guarType">
|
||||
<el-select v-model="queryParams.guarType" placeholder="请选择担保方式" clearable style="width: 160px">
|
||||
<el-option label="信用" value="信用" />
|
||||
<el-option label="保证" value="保证" />
|
||||
@@ -23,15 +31,15 @@
|
||||
<el-option label="质押" value="质押" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建者" prop="createBy">
|
||||
<el-form-item v-if="showAllSearchItems" label="创建者" prop="createBy">
|
||||
<el-input
|
||||
v-model="queryParams.createBy"
|
||||
placeholder="请输入创建者"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
@keydown.enter.native.prevent="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="机构号" prop="deptId">
|
||||
<el-form-item v-if="showAllSearchItems" label="机构号" prop="deptId">
|
||||
<treeselect
|
||||
v-model="queryParams.deptId"
|
||||
:options="deptOptions"
|
||||
@@ -41,7 +49,7 @@
|
||||
style="width: 220px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间">
|
||||
<el-form-item v-if="showAllSearchItems" label="创建时间">
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
type="daterange"
|
||||
@@ -53,7 +61,7 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" native-type="submit">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@@ -218,8 +226,12 @@ export default {
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'name',
|
||||
'nickName'
|
||||
'nickName',
|
||||
'roles'
|
||||
]),
|
||||
showAllSearchItems() {
|
||||
return !this.roles.includes('common')
|
||||
},
|
||||
currentCreateBy() {
|
||||
return `${this.nickName}-${this.name}`
|
||||
}
|
||||
|
||||
@@ -19,10 +19,12 @@ assert(
|
||||
)
|
||||
|
||||
assert(
|
||||
!personalCreateDialog.includes('label="贷款用途"') &&
|
||||
!personalCreateDialog.includes('prop="loanPurpose"') &&
|
||||
!personalCreateDialog.includes('loanPurpose:'),
|
||||
'个人新增弹窗不应继续保留贷款用途字段'
|
||||
personalCreateDialog.includes('label="贷款用途"') &&
|
||||
personalCreateDialog.includes('prop="loanPurpose"') &&
|
||||
personalCreateDialog.includes('loanPurpose: undefined') &&
|
||||
personalCreateDialog.includes('loanPurpose: this.editData.loanPurpose') &&
|
||||
personalCreateDialog.includes('请选择贷款用途'),
|
||||
'个人新增弹窗缺少贷款用途、必填校验或编辑回显'
|
||||
)
|
||||
|
||||
assert(
|
||||
@@ -31,8 +33,9 @@ assert(
|
||||
)
|
||||
|
||||
assert(
|
||||
!personalCreateDialog.includes("value=\"consumer\"") && !personalCreateDialog.includes("value=\"business\""),
|
||||
'个人新增弹窗不应继续保留贷款用途选项'
|
||||
personalCreateDialog.includes('label="经营" value="business"') &&
|
||||
personalCreateDialog.includes('label="消费" value="consumer"'),
|
||||
'个人新增弹窗贷款用途选项或协议值不正确'
|
||||
)
|
||||
|
||||
assert(
|
||||
@@ -52,25 +55,49 @@ assert(
|
||||
|
||||
assert(
|
||||
personalCreateDialog.includes('collateralTypeOptions') &&
|
||||
personalCreateDialog.includes("return ['一线', '一类', '二类', '三类']") &&
|
||||
personalCreateDialog.includes("return ['存单质押', '其他质押']"),
|
||||
'个人新增弹窗抵质押类型选项未按担保方式动态切换'
|
||||
'个人新增弹窗应保留质押类型选项'
|
||||
)
|
||||
|
||||
assert(
|
||||
personalCreateDialog.includes('{required: true, message: "请选择抵质押类型", trigger: "change"}'),
|
||||
'个人新增弹窗抵质押类型应为必填'
|
||||
personalCreateDialog.includes('label="抵押物性质"') &&
|
||||
personalCreateDialog.includes('prop="collateralNature"') &&
|
||||
personalCreateDialog.includes("return ['普通住宅、土地、厂房', '商业性质不动产', '其他抵押财产']") &&
|
||||
personalCreateDialog.includes('label="是否属于九地"') &&
|
||||
personalCreateDialog.includes('九地是指绍兴、杭州、宁波、上海、北京、广州、深圳、南京、苏州') &&
|
||||
personalCreateDialog.includes(':disabled="!requiresNineArea"') &&
|
||||
personalCreateDialog.includes("'无需选择'"),
|
||||
'个人新增弹窗缺少抵押物性质、九地选择或九地说明'
|
||||
)
|
||||
|
||||
assert(
|
||||
!personalCreateDialog.includes('label="是否有经营佐证"') &&
|
||||
!personalCreateDialog.includes('prop="bizProof"') &&
|
||||
!personalCreateDialog.includes('bizProof:') &&
|
||||
personalCreateDialog.includes("return this.form.isNineArea === '是' ? '一类' : '二类'") &&
|
||||
personalCreateDialog.includes("return this.form.isNineArea === '是' ? '二类' : '三类'") &&
|
||||
personalCreateDialog.includes("return '四类'"),
|
||||
'个人新增弹窗抵押物类型映射不完整'
|
||||
)
|
||||
|
||||
assert(
|
||||
personalCreateDialog.includes("if (this.isPledge && !value)") &&
|
||||
personalCreateDialog.includes("if (this.isMortgage && !value)") &&
|
||||
personalCreateDialog.includes("if (this.requiresNineArea && !value)"),
|
||||
'个人新增弹窗缺少抵押和质押的条件校验'
|
||||
)
|
||||
|
||||
assert(
|
||||
personalCreateDialog.includes('label="是否有营业执照"') &&
|
||||
personalCreateDialog.includes('prop="bizProof"') &&
|
||||
personalCreateDialog.includes('bizProof: false') &&
|
||||
personalCreateDialog.includes('bizProof: this.isOne(this.editData.bizProof)') &&
|
||||
personalCreateDialog.includes("bizProof: this.form.bizProof ? '1' : '0'") &&
|
||||
personalCreateDialog.includes("loanLoop: this.form.loanLoop ? '1' : '0'") &&
|
||||
personalCreateDialog.includes("data.collThirdParty = this.form.collThirdParty ? '1' : '0'") &&
|
||||
personalCreateDialog.includes('data.collType = this.resolveMortgageCollateralType()') &&
|
||||
personalCreateDialog.includes('collateralNature: this.editData.collateralNature') &&
|
||||
personalCreateDialog.includes('isNineArea: this.editData.isNineArea') &&
|
||||
personalCreateDialog.includes('delete data.collType') &&
|
||||
personalCreateDialog.includes('delete data.collThirdParty'),
|
||||
'个人新增弹窗开关字段或非抵质押提交字段处理不正确'
|
||||
'个人新增弹窗营业执照、抵押来源字段、开关字段或非抵质押提交字段处理不正确'
|
||||
)
|
||||
|
||||
assert(
|
||||
@@ -78,6 +105,19 @@ assert(
|
||||
'个人详情页缺少贷款用途展示'
|
||||
)
|
||||
|
||||
assert(
|
||||
personalDetail.includes('label="是否有营业执照"') && personalDetail.includes('detailData.bizProof'),
|
||||
'个人详情页缺少营业执照展示'
|
||||
)
|
||||
|
||||
assert(
|
||||
personalDetail.includes('label="抵押物性质"') &&
|
||||
personalDetail.includes('detailData.collateralNature') &&
|
||||
personalDetail.includes('label="是否属于九地"') &&
|
||||
personalDetail.includes('detailData.isNineArea'),
|
||||
'个人详情页缺少抵押物性质或九地展示'
|
||||
)
|
||||
|
||||
assert(
|
||||
personalDetail.includes("value === '1'") && personalDetail.includes("value === '0'"),
|
||||
'个人详情页布尔格式化未兼容 1/0'
|
||||
|
||||
@@ -7,15 +7,22 @@ function read(relativePath) {
|
||||
}
|
||||
|
||||
const personalDetail = read('src/views/loanPricing/workflow/components/PersonalWorkflowDetail.vue')
|
||||
const summaryStart = personalDetail.indexOf('<el-card class="summary-card">')
|
||||
const summaryEnd = personalDetail.indexOf('</el-card>', summaryStart)
|
||||
const summaryCard = personalDetail.slice(summaryStart, summaryEnd)
|
||||
|
||||
assert(summaryStart !== -1 && summaryEnd !== -1, '个人流程详情缺少关键信息卡片')
|
||||
|
||||
assert(
|
||||
/label="最终测算利率"/.test(personalDetail),
|
||||
'个人流程详情左侧缺少“最终测算利率”标签'
|
||||
!/label="(?:基准利率|浮动BP|最终测算利率)"/.test(summaryCard),
|
||||
'个人流程详情关键信息不应展示基准利率、浮动BP或最终测算利率'
|
||||
)
|
||||
|
||||
assert(
|
||||
/return this\.retailOutput\?\.finalCalculateRate \|\| '-'/.test(personalDetail),
|
||||
'个人流程详情没有使用 finalCalculateRate 展示最终测算利率'
|
||||
/label="期限"/.test(summaryCard)
|
||||
&& /label="担保方式"/.test(summaryCard)
|
||||
&& /label="产品最低利率下限"/.test(summaryCard),
|
||||
'个人流程详情关键信息缺少期限、担保方式或产品最低利率下限'
|
||||
)
|
||||
|
||||
console.log('personal final calculate rate display assertions passed')
|
||||
console.log('personal key information display assertions passed')
|
||||
|
||||
@@ -9,18 +9,55 @@ function read(relativePath) {
|
||||
const personalDetail = read('src/views/loanPricing/workflow/components/PersonalWorkflowDetail.vue')
|
||||
const modelOutput = read('src/views/loanPricing/workflow/components/ModelOutputDisplay.vue')
|
||||
|
||||
function extractCard(source, className) {
|
||||
const start = source.indexOf(`<el-card class="${className}">`)
|
||||
const end = source.indexOf('</el-card>', start)
|
||||
assert(start !== -1 && end !== -1, `缺少卡片: ${className}`)
|
||||
return source.slice(start, end)
|
||||
}
|
||||
|
||||
const summaryCard = extractCard(personalDetail, 'summary-card')
|
||||
const detailCard = extractCard(personalDetail, 'detail-card')
|
||||
const businessInfoStart = detailCard.indexOf('<h4 class="section-title">业务信息</h4>')
|
||||
const basicInfo = detailCard.slice(0, businessInfoStart)
|
||||
const businessInfo = detailCard.slice(businessInfoStart)
|
||||
|
||||
assert(
|
||||
personalDetail.includes('label="借款期限"') && personalDetail.includes('detailData.loanTerm'),
|
||||
'个人详情页缺少借款期限展示'
|
||||
!basicInfo.includes('label="借款期限"')
|
||||
&& businessInfo.includes('label="借款期限"')
|
||||
&& businessInfo.includes('detailData.loanTerm'),
|
||||
'个人详情页借款期限未展示在业务信息中'
|
||||
)
|
||||
|
||||
;['期限', '担保方式', '产品最低利率下限'].forEach((label) => {
|
||||
assert(summaryCard.includes(`label="${label}"`), `个人流程详情关键信息缺少字段: ${label}`)
|
||||
})
|
||||
|
||||
;['基准利率', '浮动BP', '最终测算利率'].forEach((label) => {
|
||||
assert(!summaryCard.includes(`label="${label}"`), `个人流程详情关键信息不应展示字段: ${label}`)
|
||||
})
|
||||
|
||||
assert(
|
||||
personalDetail.includes('formatRate(retailOutput && retailOutput.minRateProduct)'),
|
||||
'个人流程详情关键信息未展示产品最低利率下限'
|
||||
)
|
||||
|
||||
assert(
|
||||
personalDetail.includes(':guar-type="detailData.guarType"'),
|
||||
'个人模型输出未使用流程担保方式控制抵押物行'
|
||||
)
|
||||
|
||||
const requiredRetailFields = [
|
||||
'retailOutput.greyBlackCust',
|
||||
'retailOutput.loanRateHistory',
|
||||
'retailOutput.minRateProduct',
|
||||
'retailOutput.smoothRange',
|
||||
'retailOutput.finalCalculateRate',
|
||||
'retailOutput.referenceRate'
|
||||
'retailOutput.referenceRate',
|
||||
'retailOutput.branchBp',
|
||||
'retailOutput.bpLoanUse',
|
||||
'retailOutput.midPerGasDdc',
|
||||
'retailOutput.bpPrinOverdue',
|
||||
'retailOutput.bpIinterestOverdue',
|
||||
'retailOutput.bpCardOverdue'
|
||||
]
|
||||
|
||||
requiredRetailFields.forEach((field) => {
|
||||
@@ -28,9 +65,34 @@ requiredRetailFields.forEach((field) => {
|
||||
})
|
||||
|
||||
assert(
|
||||
modelOutput.indexOf('label="灰黑名单客户"') > modelOutput.indexOf('<h4 class="section-title">基本信息</h4>')
|
||||
&& modelOutput.indexOf('label="灰黑名单客户"') < modelOutput.indexOf('<h4 class="section-title">测算结果</h4>'),
|
||||
'灰黑名单客户未展示在个人模型输出基础信息中'
|
||||
modelOutput.includes("this.resultItem('营业执照', this.formatBoolean(this.retailOutput.bizProof))"),
|
||||
'个人风险度缺少营业执照或 BP_贷款用途关联展示'
|
||||
)
|
||||
|
||||
assert(
|
||||
basicInfo.includes('label="灰名单客户"')
|
||||
&& basicInfo.includes('retailOutput && retailOutput.greyCust')
|
||||
&& basicInfo.includes('label="黑名单客户"')
|
||||
&& basicInfo.includes('retailOutput && retailOutput.blackCust'),
|
||||
'个人流程详情基本信息缺少灰名单客户或黑名单客户'
|
||||
)
|
||||
|
||||
assert(
|
||||
!modelOutput.includes("this.resultItem('灰名单客户', this.formatBoolean(this.retailOutput.greyCust))")
|
||||
&& !modelOutput.includes("this.resultItem('黑名单客户', this.formatBoolean(this.retailOutput.blackCust))")
|
||||
&& !modelOutput.includes("'BP_灰名单与逾期', this.retailOutput.bpGreyOverdue"),
|
||||
'个人风险度不应继续展示灰黑客户或旧聚合BP'
|
||||
)
|
||||
|
||||
assert(
|
||||
!basicInfo.includes('label="基准利率"')
|
||||
&& !basicInfo.includes('retailOutput && retailOutput.baseLoanRate'),
|
||||
'个人流程详情基本信息不应展示基准利率'
|
||||
)
|
||||
|
||||
assert(
|
||||
!detailCard.includes('label="运行模式"') && !modelOutput.includes('<h4 class="section-title">基本信息</h4>'),
|
||||
'个人详情仍展示运行模式或模型输出基本信息'
|
||||
)
|
||||
|
||||
console.log('retail display fields assertions passed')
|
||||
|
||||
@@ -6,22 +6,22 @@ function read(relativePath) {
|
||||
return fs.readFileSync(path.join(__dirname, '..', relativePath), 'utf8')
|
||||
}
|
||||
|
||||
function assertModelOutputBeforeDetailCard(source, label) {
|
||||
function assertDetailCardBeforeModelOutput(source, label) {
|
||||
const modelOutputIndex = source.indexOf('<ModelOutputDisplay')
|
||||
const detailCardIndex = source.indexOf('<el-card class="detail-card">')
|
||||
|
||||
assert(modelOutputIndex !== -1, `${label} 缺少模型输出卡片`)
|
||||
assert(detailCardIndex !== -1, `${label} 缺少流程详情卡片`)
|
||||
assert(
|
||||
modelOutputIndex < detailCardIndex,
|
||||
`${label} 的模型输出卡片应位于流程详情卡片上方`
|
||||
detailCardIndex < modelOutputIndex,
|
||||
`${label} 的流程详情卡片应位于模型输出卡片上方`
|
||||
)
|
||||
}
|
||||
|
||||
const personalDetail = read('src/views/loanPricing/workflow/components/PersonalWorkflowDetail.vue')
|
||||
const corporateDetail = read('src/views/loanPricing/workflow/components/CorporateWorkflowDetail.vue')
|
||||
|
||||
assertModelOutputBeforeDetailCard(personalDetail, '个人流程详情')
|
||||
assertModelOutputBeforeDetailCard(corporateDetail, '企业流程详情')
|
||||
assertDetailCardBeforeModelOutput(personalDetail, '个人流程详情')
|
||||
assertDetailCardBeforeModelOutput(corporateDetail, '企业流程详情')
|
||||
|
||||
console.log('workflow detail card order assertions passed')
|
||||
|
||||
@@ -63,6 +63,15 @@ assert(source.includes('beginCreateTime: hasDateRange ? `${this.dateRange[0]} 00
|
||||
assert(source.includes('endCreateTime: hasDateRange ? `${this.dateRange[1]} 23:59:59` : undefined'), '流程列表应传递当天末秒的顶层创建时间结束参数')
|
||||
assert(source.includes('label="机构号"') && source.includes('prop="deptId"'), '流程列表应展示机构号')
|
||||
assert(source.indexOf('label="机构号"') > source.indexOf('label="创建者"'), '机构号列应位于创建者列之后')
|
||||
assert.strictEqual((source.match(/v-if="showAllSearchItems"/g) || []).length, 5, '五个高级搜索项均应根据角色显示')
|
||||
|
||||
assert.strictEqual(component.computed.showAllSearchItems.call({
|
||||
roles: ['common']
|
||||
}), false, '客户经理只应展示客户信息搜索项')
|
||||
|
||||
assert.strictEqual(component.computed.showAllSearchItems.call({
|
||||
roles: ['headAdmin']
|
||||
}), true, '其他角色应展示全部搜索项')
|
||||
|
||||
let refreshCount = 0
|
||||
component.activated.call({
|
||||
|
||||
16
sql/20260814-production.sql
Normal file
16
sql/20260814-production.sql
Normal file
@@ -0,0 +1,16 @@
|
||||
-- 2026-08-14 production database changes
|
||||
|
||||
-- Personal model output fields
|
||||
ALTER TABLE `model_retail_output_fields`
|
||||
ADD COLUMN `black_cust` varchar(100) DEFAULT NULL COMMENT '黑名单客户' AFTER `grey_cust`,
|
||||
ADD COLUMN `branch_bp` varchar(100) DEFAULT NULL COMMENT '行社下调BP' AFTER `reference_rate`;
|
||||
|
||||
-- Corporate model output fields
|
||||
ALTER TABLE `model_corp_output_fields`
|
||||
ADD COLUMN `black_cust` varchar(100) DEFAULT NULL COMMENT '黑名单客户' AFTER `grey_cust`,
|
||||
ADD COLUMN `branch_bp` varchar(100) DEFAULT NULL COMMENT '行社下调BP' AFTER `reference_rate`;
|
||||
|
||||
-- Workflow collateral source fields
|
||||
ALTER TABLE `loan_pricing_workflow`
|
||||
ADD COLUMN `collateral_nature` varchar(50) DEFAULT NULL COMMENT '抵押物性质' AFTER `loan_loop`,
|
||||
ADD COLUMN `is_nine_area` varchar(10) DEFAULT NULL COMMENT '是否属于九地: 是/否' AFTER `collateral_nature`;
|
||||
5
sql/20260824-corporate-workflow-optimization.sql
Normal file
5
sql/20260824-corporate-workflow-optimization.sql
Normal file
@@ -0,0 +1,5 @@
|
||||
-- 2026-08-24 corporate model output overdue BP fields
|
||||
ALTER TABLE `model_corp_output_fields`
|
||||
ADD COLUMN `bp_prin_overdue` varchar(100) DEFAULT NULL COMMENT 'BP_本金逾期' AFTER `prin_overdue`,
|
||||
ADD COLUMN `bp_iinterest_overdue` varchar(100) DEFAULT NULL COMMENT 'BP_利息逾期' AFTER `interest_overdue`,
|
||||
ADD COLUMN `bp_card_overdue` varchar(100) DEFAULT NULL COMMENT 'BP_信用卡逾期' AFTER `card_overdue`;
|
||||
5
sql/20260824-personal-workflow-optimization.sql
Normal file
5
sql/20260824-personal-workflow-optimization.sql
Normal file
@@ -0,0 +1,5 @@
|
||||
-- 2026-08-24 personal model output overdue BP fields
|
||||
ALTER TABLE `model_retail_output_fields`
|
||||
ADD COLUMN `bp_prin_overdue` varchar(100) DEFAULT NULL COMMENT 'BP_本金逾期' AFTER `prin_overdue`,
|
||||
ADD COLUMN `bp_iinterest_overdue` varchar(100) DEFAULT NULL COMMENT 'BP_利息逾期' AFTER `interest_overdue`,
|
||||
ADD COLUMN `bp_card_overdue` varchar(100) DEFAULT NULL COMMENT 'BP_信用卡逾期' AFTER `card_overdue`;
|
||||
Reference in New Issue
Block a user