调整个人最终测算利率展示并重排详情卡片
This commit is contained in:
@@ -0,0 +1,19 @@
|
|||||||
|
# 个人流程最终测算利率展示实施记录
|
||||||
|
|
||||||
|
## 修改时间
|
||||||
|
- 2026-04-11
|
||||||
|
|
||||||
|
## 修改内容
|
||||||
|
- 调整流程列表后端查询:个人客户列表“测算利率”改为读取 `model_retail_output_fields.final_calculate_rate`
|
||||||
|
- 调整个人流程详情左侧展示:标签改为“最终测算利率”,显示字段改为 `retailOutput.finalCalculateRate`
|
||||||
|
- 调整个人流程详情后端组装:`loanPricingWorkflow.loanRate` 改为取个人模型输出的 `finalCalculateRate`
|
||||||
|
|
||||||
|
## 影响范围
|
||||||
|
- 个人流程列表
|
||||||
|
- 个人流程详情左侧关键信息
|
||||||
|
- 企业流程列表与详情保持现状,不做改动
|
||||||
|
|
||||||
|
## 验证计划
|
||||||
|
- 后端单元测试验证个人详情取 `finalCalculateRate`
|
||||||
|
- 后端静态测试验证列表 SQL 的个人分支查询 `mr.final_calculate_rate`
|
||||||
|
- 前端静态测试验证个人详情展示 `finalCalculateRate`
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# 流程详情卡片顺序调整实施记录
|
||||||
|
|
||||||
|
## 修改时间
|
||||||
|
- 2026-04-11
|
||||||
|
|
||||||
|
## 修改内容
|
||||||
|
- 调整个人流程详情页右侧卡片顺序,将模型输出卡片移动到流程详情卡片上方
|
||||||
|
- 调整企业流程详情页右侧卡片顺序,将模型输出卡片移动到流程详情卡片上方
|
||||||
|
- 新增前端静态校验,约束个人与企业详情组件的卡片顺序
|
||||||
|
|
||||||
|
## 影响范围
|
||||||
|
- 个人流程详情页面布局
|
||||||
|
- 企业流程详情页面布局
|
||||||
|
|
||||||
|
## 验证计划
|
||||||
|
- 执行前端静态测试,确认卡片顺序断言通过
|
||||||
|
- 启动前端页面并在浏览器中检查个人、企业详情页卡片顺序
|
||||||
@@ -172,7 +172,7 @@ public class LoanPricingWorkflowServiceImpl implements ILoanPricingWorkflowServi
|
|||||||
if (Objects.nonNull(modelRetailOutputFields))
|
if (Objects.nonNull(modelRetailOutputFields))
|
||||||
{
|
{
|
||||||
maskModelRetailOutputBasicInfo(modelRetailOutputFields);
|
maskModelRetailOutputBasicInfo(modelRetailOutputFields);
|
||||||
loanPricingWorkflow.setLoanRate(modelRetailOutputFields.getCalculateRate());
|
loanPricingWorkflow.setLoanRate(modelRetailOutputFields.getFinalCalculateRate());
|
||||||
}
|
}
|
||||||
loanPricingWorkflowVO.setModelRetailOutputFields(modelRetailOutputFields);
|
loanPricingWorkflowVO.setModelRetailOutputFields(modelRetailOutputFields);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
lpw.guar_type AS guarType,
|
lpw.guar_type AS guarType,
|
||||||
lpw.apply_amt AS applyAmt,
|
lpw.apply_amt AS applyAmt,
|
||||||
CASE
|
CASE
|
||||||
WHEN lpw.cust_type = '个人' THEN mr.calculate_rate
|
WHEN lpw.cust_type = '个人' THEN mr.final_calculate_rate
|
||||||
WHEN lpw.cust_type = '企业' THEN mc.calculate_rate
|
WHEN lpw.cust_type = '企业' THEN mc.calculate_rate
|
||||||
ELSE NULL
|
ELSE NULL
|
||||||
END AS calculateRate,
|
END AS calculateRate,
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.ruoyi.loanpricing.mapper;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
import org.springframework.util.StreamUtils;
|
||||||
|
|
||||||
|
class LoanPricingWorkflowMapperXmlTest
|
||||||
|
{
|
||||||
|
@Test
|
||||||
|
void shouldUseRetailFinalCalculateRateInWorkflowListQuery() throws IOException
|
||||||
|
{
|
||||||
|
ClassPathResource resource = new ClassPathResource("mapper/loanpricing/LoanPricingWorkflowMapper.xml");
|
||||||
|
String xml = StreamUtils.copyToString(resource.getInputStream(), StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
assertTrue(xml.contains("WHEN lpw.cust_type = '个人' THEN mr.final_calculate_rate"));
|
||||||
|
assertTrue(xml.contains("WHEN lpw.cust_type = '企业' THEN mc.calculate_rate"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -134,7 +134,7 @@ class LoanPricingWorkflowServiceImplTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldUseRetailModelOutputCalculateRateForWorkflowDetail()
|
void shouldUseRetailModelOutputFinalCalculateRateForWorkflowDetail()
|
||||||
{
|
{
|
||||||
LoanPricingWorkflow workflow = new LoanPricingWorkflow();
|
LoanPricingWorkflow workflow = new LoanPricingWorkflow();
|
||||||
workflow.setSerialNum("P20260328001");
|
workflow.setSerialNum("P20260328001");
|
||||||
@@ -144,14 +144,16 @@ class LoanPricingWorkflowServiceImplTest
|
|||||||
|
|
||||||
ModelRetailOutputFields retailOutputFields = new ModelRetailOutputFields();
|
ModelRetailOutputFields retailOutputFields = new ModelRetailOutputFields();
|
||||||
retailOutputFields.setCalculateRate("6.15");
|
retailOutputFields.setCalculateRate("6.15");
|
||||||
|
retailOutputFields.setFinalCalculateRate("6.05");
|
||||||
|
|
||||||
when(loanPricingWorkflowMapper.selectOne(any())).thenReturn(workflow);
|
when(loanPricingWorkflowMapper.selectOne(any())).thenReturn(workflow);
|
||||||
when(modelRetailOutputFieldsMapper.selectById(11L)).thenReturn(retailOutputFields);
|
when(modelRetailOutputFieldsMapper.selectById(11L)).thenReturn(retailOutputFields);
|
||||||
|
|
||||||
LoanPricingWorkflowVO result = loanPricingWorkflowService.selectLoanPricingBySerialNum("P20260328001");
|
LoanPricingWorkflowVO result = loanPricingWorkflowService.selectLoanPricingBySerialNum("P20260328001");
|
||||||
|
|
||||||
assertEquals("6.15", result.getLoanPricingWorkflow().getLoanRate());
|
assertEquals("6.05", result.getLoanPricingWorkflow().getLoanRate());
|
||||||
assertEquals("6.15", result.getModelRetailOutputFields().getCalculateRate());
|
assertEquals("6.15", result.getModelRetailOutputFields().getCalculateRate());
|
||||||
|
assertEquals("6.05", result.getModelRetailOutputFields().getFinalCalculateRate());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -46,6 +46,13 @@
|
|||||||
|
|
||||||
<!-- 右侧面板 -->
|
<!-- 右侧面板 -->
|
||||||
<div class="right-panel">
|
<div class="right-panel">
|
||||||
|
<!-- 模型输出卡片 -->
|
||||||
|
<ModelOutputDisplay
|
||||||
|
:cust-type="detailData.custType"
|
||||||
|
:retail-output="null"
|
||||||
|
:corp-output="corpOutput"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- 流程详情卡片 -->
|
<!-- 流程详情卡片 -->
|
||||||
<el-card class="detail-card">
|
<el-card class="detail-card">
|
||||||
<div slot="header" class="card-header">
|
<div slot="header" class="card-header">
|
||||||
@@ -88,13 +95,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<!-- 模型输出卡片 -->
|
|
||||||
<ModelOutputDisplay
|
|
||||||
:cust-type="detailData.custType"
|
|
||||||
:retail-output="null"
|
|
||||||
:corp-output="corpOutput"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- 议价池卡片 -->
|
<!-- 议价池卡片 -->
|
||||||
<BargainingPoolDisplay
|
<BargainingPoolDisplay
|
||||||
v-if="bargainingPool"
|
v-if="bargainingPool"
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
<el-descriptions-item label="浮动BP">
|
<el-descriptions-item label="浮动BP">
|
||||||
<span class="total-bp-value">{{ getTotalBp() }}</span>
|
<span class="total-bp-value">{{ getTotalBp() }}</span>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="测算利率">
|
<el-descriptions-item label="最终测算利率">
|
||||||
<span class="calculate-rate">{{ getCalculateRate() }}</span> %
|
<span class="calculate-rate">{{ getCalculateRate() }}</span> %
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="执行利率">
|
<el-descriptions-item label="执行利率">
|
||||||
@@ -46,6 +46,13 @@
|
|||||||
|
|
||||||
<!-- 右侧面板 -->
|
<!-- 右侧面板 -->
|
||||||
<div class="right-panel">
|
<div class="right-panel">
|
||||||
|
<!-- 模型输出卡片 -->
|
||||||
|
<ModelOutputDisplay
|
||||||
|
:cust-type="detailData.custType"
|
||||||
|
:retail-output="retailOutput"
|
||||||
|
:corp-output="null"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- 流程详情卡片 -->
|
<!-- 流程详情卡片 -->
|
||||||
<el-card class="detail-card">
|
<el-card class="detail-card">
|
||||||
<div slot="header" class="card-header">
|
<div slot="header" class="card-header">
|
||||||
@@ -88,13 +95,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<!-- 模型输出卡片 -->
|
|
||||||
<ModelOutputDisplay
|
|
||||||
:cust-type="detailData.custType"
|
|
||||||
:retail-output="retailOutput"
|
|
||||||
:corp-output="null"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- 议价池卡片 -->
|
<!-- 议价池卡片 -->
|
||||||
<BargainingPoolDisplay
|
<BargainingPoolDisplay
|
||||||
v-if="bargainingPool"
|
v-if="bargainingPool"
|
||||||
@@ -168,9 +168,9 @@ export default {
|
|||||||
getTotalBp() {
|
getTotalBp() {
|
||||||
return this.retailOutput?.totalBp || '-'
|
return this.retailOutput?.totalBp || '-'
|
||||||
},
|
},
|
||||||
/** 获取测算利率 */
|
/** 获取最终测算利率 */
|
||||||
getCalculateRate() {
|
getCalculateRate() {
|
||||||
return this.retailOutput?.calculateRate || '-'
|
return this.retailOutput?.finalCalculateRate || '-'
|
||||||
},
|
},
|
||||||
/** 设定执行利率 */
|
/** 设定执行利率 */
|
||||||
handleSetExecuteRate() {
|
handleSetExecuteRate() {
|
||||||
|
|||||||
21
ruoyi-ui/tests/personal-final-calculate-rate-display.test.js
Normal file
21
ruoyi-ui/tests/personal-final-calculate-rate-display.test.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
|
const assert = require('assert')
|
||||||
|
|
||||||
|
function read(relativePath) {
|
||||||
|
return fs.readFileSync(path.join(__dirname, '..', relativePath), 'utf8')
|
||||||
|
}
|
||||||
|
|
||||||
|
const personalDetail = read('src/views/loanPricing/workflow/components/PersonalWorkflowDetail.vue')
|
||||||
|
|
||||||
|
assert(
|
||||||
|
/label="最终测算利率"/.test(personalDetail),
|
||||||
|
'个人流程详情左侧缺少“最终测算利率”标签'
|
||||||
|
)
|
||||||
|
|
||||||
|
assert(
|
||||||
|
/return this\.retailOutput\?\.finalCalculateRate \|\| '-'/.test(personalDetail),
|
||||||
|
'个人流程详情没有使用 finalCalculateRate 展示最终测算利率'
|
||||||
|
)
|
||||||
|
|
||||||
|
console.log('personal final calculate rate display assertions passed')
|
||||||
27
ruoyi-ui/tests/workflow-detail-card-order.test.js
Normal file
27
ruoyi-ui/tests/workflow-detail-card-order.test.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
|
const assert = require('assert')
|
||||||
|
|
||||||
|
function read(relativePath) {
|
||||||
|
return fs.readFileSync(path.join(__dirname, '..', relativePath), 'utf8')
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertModelOutputBeforeDetailCard(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} 的模型输出卡片应位于流程详情卡片上方`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const personalDetail = read('src/views/loanPricing/workflow/components/PersonalWorkflowDetail.vue')
|
||||||
|
const corporateDetail = read('src/views/loanPricing/workflow/components/CorporateWorkflowDetail.vue')
|
||||||
|
|
||||||
|
assertModelOutputBeforeDetailCard(personalDetail, '个人流程详情')
|
||||||
|
assertModelOutputBeforeDetailCard(corporateDetail, '企业流程详情')
|
||||||
|
|
||||||
|
console.log('workflow detail card order assertions passed')
|
||||||
Reference in New Issue
Block a user