模型输出展示

This commit is contained in:
wkc
2026-01-22 09:20:28 +08:00
parent 0d061155ed
commit a0fd1d0e4e
9 changed files with 1014 additions and 102 deletions

View File

@@ -15,7 +15,9 @@
"Bash(openspec archive add-loan-pricing-create:*)",
"Bash(git add:*)",
"Bash(cd:*)",
"mcp__zai-mcp-server__extract_text_from_screenshot"
"mcp__zai-mcp-server__extract_text_from_screenshot",
"Bash(npx openspec validate:*)",
"Bash(npx openspec show:*)"
],
"additionalDirectories": [
"d:\\利率定价\\loan-pricing-892\\loan-pricing-892-v2.0"

View File

@@ -74,6 +74,8 @@
"code": 200,
"msg": "操作成功",
"data": {
"id": 1,
"modelOutputId": 100,
"serialNum": "20250119143025123",
"orgCode": "931000",
"runType": "1",
@@ -108,6 +110,8 @@
| createBy | String | 否 | 创建者(筛选条件) |
| custName | String | 否 | 客户名称(模糊查询) |
| orgCode | String | 否 | 机构号(筛选条件) |
| custType | String | 否 | 客户类型(筛选条件) |
| guarType | String | 否 | 担保方式(筛选条件) |
**请求示例:**
@@ -123,6 +127,8 @@ GET /loanPricing/workflow/list?pageNum=1&pageSize=10&custName=科技
"msg": "查询成功",
"rows": [
{
"id": 1,
"modelOutputId": 100,
"serialNum": "20250119143025123",
"orgCode": "931000",
"custIsn": "CUST001",
@@ -146,7 +152,7 @@ GET /loanPricing/workflow/list?pageNum=1&pageSize=10&custName=科技
### 3. 查看利率定价流程详情
根据业务方流水号查询流程的完整信息。
根据业务方流水号查询流程的完整信息,包括模型输出字段
**接口地址:** `GET /loanPricing/workflow/{serialNum}`
@@ -171,39 +177,152 @@ GET /loanPricing/workflow/20250119143025123
"code": 200,
"msg": "查询成功",
"data": {
"serialNum": "20250119143025123",
"orgCode": "931000",
"runType": "1",
"custIsn": "CUST001",
"custType": "企业",
"guarType": "抵押",
"midPerQuickPay": "false",
"midPerEleDdc": "false",
"midEntEleDdc": "false",
"midEntWaterDdc": "false",
"applyAmt": "1000000",
"isCleanEnt": "false",
"hasSettleAcct": "false",
"isManufacturing": "true",
"isAgriGuar": "false",
"isTaxA": "false",
"isAgriLeading": "false",
"loanPurpose": "business",
"bizProof": "true",
"collType": "一类",
"collThirdParty": "false",
"loanRate": "4.35",
"custName": "某某科技有限公司",
"idType": "统一社会信用代码",
"isInclusiveFinance": "true",
"createTime": "2025-01-19 14:30:25",
"createBy": "admin",
"updateTime": "2025-01-19 15:20:10",
"updateBy": "admin"
"loanPricingWorkflow": {
"id": 1,
"modelOutputId": 100,
"serialNum": "20250119143025123",
"orgCode": "931000",
"runType": "1",
"custIsn": "CUST001",
"custType": "企业",
"guarType": "抵押",
"midPerQuickPay": "false",
"midPerEleDdc": "false",
"midEntEleDdc": "false",
"midEntWaterDdc": "false",
"applyAmt": "1000000",
"isCleanEnt": "false",
"hasSettleAcct": "false",
"isManufacturing": "true",
"isAgriGuar": "false",
"isTaxA": "false",
"isAgriLeading": "false",
"loanPurpose": "business",
"bizProof": "true",
"collType": "一类",
"collThirdParty": "false",
"loanRate": "4.35",
"custName": "某某科技有限公司",
"idType": "统一社会信用代码",
"isInclusiveFinance": "true",
"createTime": "2025-01-19 14:30:25",
"createBy": "admin",
"updateTime": "2025-01-19 15:20:10",
"updateBy": "admin"
},
"modelRetailOutputFields": {
"id": 1,
"custIsn": "CUST001",
"custType": "个人",
"custName": "张三",
"idType": "身份证",
"idNum": "330102199001011234",
"baseLoanRate": "3.45",
"isFirstLoan": "true",
"faithDay": "365",
"custAge": "35",
"bpFirstLoan": "-10",
"bpAgeLoan": "-5",
"bpAge": "0",
"totalBpLoyalty": "-15",
"balanceAvg": "50000",
"loanAvg": "300000",
"derivationRate": "0.6",
"totalBpContribution": "-20",
"midPerCard": "true",
"midPerPass": "false",
"midPerHarvest": "true",
"midPerEffect": "true",
"midPerQuickPay": "false",
"midPerEleDdc": "false",
"midPerWaterDdc": "false",
"midPerHuashuDdc": "false",
"MidPerGasDdc": "false",
"midPerCitizencard": "true",
"midPerFinMan": "false",
"midPerEtc": "true",
"bpMid": "-15",
"totoalBpRelevance": "-50",
"applyAmt": "500000",
"bpLoanAmount": "0",
"loanPurpose": "consumer",
"bizProof": "false",
"bpLoanUse": "0",
"loanLoop": "false",
"bpLoanLoop": "0",
"collType": "一类",
"collThirdParty": "false",
"bpCollateral": "-30",
"greyCust": "false",
"prinOverdue": "false",
"interestOverdue": "false",
"cardOverdue": "false",
"bpGreyOverdue": "0",
"totoalBpRisk": "0",
"totalBp": "-80",
"calculateRate": "2.65"
},
"modelCorpOutputFields": {
"id": 2,
"custIsn": "CUST001",
"custType": "企业",
"custName": "某某科技有限公司",
"idType": "统一社会信用代码",
"idNum": "91330100MA2ABCDE01",
"baseLoanRate": "3.45",
"isFirstLoan": "false",
"faithDay": "730",
"bpFirstLoan": "0",
"bpAgeLoan": "-5",
"totalBpLoyalty": "-5",
"balanceAvg": "500000",
"loanAvg": "3000000",
"derivationRate": "0.16",
"totalBpContribution": "-30",
"midEntConnect": "true",
"midEntEffect": "true",
"midEntInter": "false",
"midEntAccept": "true",
"midEntDiscount": "false",
"midEntEleDdc": "true",
"midEntWaterDdc": "false",
"midEntTax": "true",
"bpMid": "-20",
"payroll": "50",
"invLoanAmount": "2000000",
"bpPayroll": "-10",
"isCleanEnt": "true",
"hasSettleAcct": "true",
"isAgriGuar": "false",
"isGreenLoan": "false",
"isTechEnt": "true",
"bpEntType": "-25",
"totoalBpRelevance": "-55",
"loanTerm": "36",
"bpLoanTerm": "0",
"applyAmt": "1000000",
"bpLoanAmount": "0",
"collType": "一类",
"collThirdParty": "false",
"bpCollateral": "-30",
"greyCust": "false",
"prinOverdue": "false",
"interestOverdue": "false",
"cardOverdue": "false",
"bpGreyOverdue": "0",
"totoalBpRisk": "0",
"totalBp": "-85",
"calculateRate": "2.60"
}
}
}
```
**说明:**
- `loanPricingWorkflow`: 利率定价流程基本信息
- `modelRetailOutputFields`: 个人客户模型输出字段(当 custType 为个人时返回)
- `modelCorpOutputFields`: 企业客户模型输出字段(当 custType 为企业时返回)
---
## 错误码说明
@@ -260,6 +379,12 @@ GET /loanPricing/workflow/20250119143025123
| 一类 | 一类抵押 |
| 二类 | 二类抵押 |
### 运行模式 (runType)
| 值 | 说明 |
|----|------|
| 1 | 同步运行 |
---
## 在线文档

View File

@@ -0,0 +1,160 @@
# 设计文档: 模型输出展示
## 概述
本文档描述在流程详情页面中添加模型输出展示功能的技术设计。
## 页面结构
### 当前布局
```
┌─────────────────────────────────────────────────────────┐
│ 页面标题: 流程详情 [返回按钮] │
├──────────────────────┬──────────────────────────────────┤
│ 关键信息摘要 (30%) │ 详情标签页 (70%) │
│ ┌────────────────┐ │ ┌────────────────────────────┐ │
│ │ 流水号 │ │ │ [基本信息][业务信息]... │ │
│ │ 客户名称 │ │ │ │ │
│ │ 客户类型 │ │ │ 字段内容... │ │
│ │ 申请金额 │ │ │ │ │
│ │ 贷款利率 │ │ │ │ │
│ │ 担保方式 │ │ │ │ │
│ └────────────────┘ │ └────────────────────────────┘ │
└──────────────────────┴──────────────────────────────────┘
```
### 新增布局
```
┌─────────────────────────────────────────────────────────┐
│ 页面标题: 流程详情 [返回按钮] │
├──────────────────────┬──────────────────────────────────┤
│ 关键信息摘要 (30%) │ 详情标签页 (70%) │
│ ┌────────────────┐ │ ┌────────────────────────────┐ │
│ │ 流水号 │ │ │ [基本信息][业务信息]... │ │
│ │ 客户名称 │ │ │ │ │
│ │ 客户类型 │ │ │ 字段内容... │ │
│ │ 申请金额 │ │ │ │ │
│ │ 贷款利率 │ │ │ │ │
│ │ 担保方式 │ │ │ │ │
│ └────────────────┘ │ └────────────────────────────┘ │
├──────────────────────┴──────────────────────────────────┤
│ 模型输出 (当有数据时显示) │
│ ┌────────────────────────────────────────────────────┐│
│ │ [基本信息][忠诚度分析][贡献度分析]... ││
│ │ ││
│ │ 字段内容... ││
│ └────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────┘
```
## 组件设计
### ModelOutputDisplay 组件
建议创建独立的模型输出展示组件,便于维护和复用。
```vue
<template>
<el-card v-if="shouldDisplay" class="model-output-card">
<div slot="header" class="card-header">
<span class="card-title">模型输出</span>
</div>
<el-tabs v-model="activeTab">
<!-- 个人客户 Tabs -->
<template v-if="custType === '个人'">
<el-tab-pane label="基本信息" key="retail-basic">...</el-tab-pane>
<el-tab-pane label="忠诚度分析" key="retail-loyalty">...</el-tab-pane>
<el-tab-pane label="贡献度分析" key="retail-contribution">...</el-tab-pane>
<el-tab-pane label="关联度分析" key="retail-relevance">...</el-tab-pane>
<el-tab-pane label="贷款特征" key="retail-loan">...</el-tab-pane>
<el-tab-pane label="风险度分析" key="retail-risk">...</el-tab-pane>
<el-tab-pane label="测算结果" key="retail-result">...</el-tab-pane>
</template>
<!-- 企业客户 Tabs -->
<template v-else-if="custType === '企业'">
<el-tab-pane label="基本信息" key="corp-basic">...</el-tab-pane>
<el-tab-pane label="忠诚度分析" key="corp-loyalty">...</el-tab-pane>
<el-tab-pane label="贡献度分析" key="corp-contribution">...</el-tab-pane>
<el-tab-pane label="关联度分析" key="corp-relevance">...</el-tab-pane>
<el-tab-pane label="企业类别" key="corp-category">...</el-tab-pane>
<el-tab-pane label="贷款特征" key="corp-loan">...</el-tab-pane>
<el-tab-pane label="风险度分析" key="corp-risk">...</el-tab-pane>
<el-tab-pane label="测算结果" key="corp-result">...</el-tab-pane>
</template>
</el-tabs>
</el-card>
</template>
```
## 数据流
### API 响应结构
```json
{
"code": 200,
"msg": "查询成功",
"data": {
"loanPricingWorkflow": { ... },
"modelRetailOutputFields": { ... }, // 个人客户时存在
"modelCorpOutputFields": { ... } // 企业客户时存在
}
}
```
### 组件 Props
| Prop | 类型 | 说明 |
|------|------|------|
| custType | String | 客户类型(个人/企业) |
| retailOutput | Object | 个人客户模型输出数据 |
| corpOutput | Object | 企业客户模型输出数据 |
## 样式规范
### 卡片样式
与现有 `.summary-card``.detail-card` 保持一致:
- 头部背景色: `#fafafa`
- 边框颜色: `#ebeef5`
- 内边距: 头部 `16px 20px`, 内容 `20px`
- 标题字号: `16px`, 字重 `500`
- 标题颜色: `#303133`
### Tab 样式
使用 Element UI 默认 Tab 样式,间距保持一致。
## 字段映射表
### 个人客户模型输出字段
| Tab | 字段名 | 显示标签 | 格式化 |
|-----|--------|----------|--------|
| 基本信息 | custIsn | 客户内码 | - |
| 基本信息 | custName | 客户名称 | - |
| 基本信息 | idType | 证件类型 | - |
| 基本信息 | idNum | 证件号码 | - |
| 基本信息 | baseLoanRate | 基准利率 | - |
| 测算结果 | totalBp | 浮动BP | - |
| 测算结果 | calculateRate | 测算利率 | 高亮显示 |
### 企业客户模型输出字段
| Tab | 字段名 | 显示标签 | 格式化 |
|-----|--------|----------|--------|
| 基本信息 | custIsn | 客户内码 | - |
| 基本信息 | custName | 客户名称 | - |
| 基本信息 | idType | 证件类型 | - |
| 基本信息 | idNum | 证件号码 | - |
| 基本信息 | baseLoanRate | 基准利率 | - |
| 测算结果 | totalBp | 浮动BP | - |
| 测算结果 | calculateRate | 测算利率 | 高亮显示 |
## 响应式设计
- 桌面端 (≥768px): 模型输出卡片宽度 100%Tab 内容两列布局
- 移动端 (<768px): 模型输出卡片宽度 100%Tab 内容单列布局

View File

@@ -0,0 +1,74 @@
# 提案: 在流程详情页添加模型输出展示
## 背景
利率定价流程详情接口已更新,新增了模型输出字段 (`modelRetailOutputFields``modelCorpOutputFields`)。目前前端详情页面仅展示流程基本信息,未展示模型输出数据。
## 问题
用户在查看流程详情时,无法看到模型计算的输出结果(包括各项 BP 值、测算利率等关键信息),影响业务决策和问题排查。
## 提案概述
在流程详情页面 (`/loanPricing/workflow/detail/:serialNum`) 下方新增独立的模型输出展示区域,根据客户类型(个人/企业)显示对应的模型输出字段。
### 展示逻辑
-`loanPricingWorkflow.custType === "个人"` 时,展示 `modelRetailOutputFields` 字段
-`loanPricingWorkflow.custType === "企业"` 时,展示 `modelCorpOutputFields` 字段
- 当模型输出数据为空时,隐藏该展示区域
### 布局结构
保持与现有页面风格一致,采用卡片 + Tab 标签页的形式展示模型输出字段。
#### 个人客户模型输出 Tab 分类
| Tab 名称 | 字段内容 |
|---------|---------|
| 基本信息 | 客户内码、客户名称、证件类型、证件号码、基准利率 |
| 忠诚度分析 | 我行首贷客户、用信天数、客户年龄、BP_首贷、BP_贷龄、BP_年龄、TOTAL_BP_忠诚度 |
| 贡献度分析 | 存款年日均、贷款年日均、派生率、TOTAL_BP_贡献度 |
| 关联度分析 | 中间业务_个人_信用卡、中间业务_个人_一码通、中间业务_个人_丰收互联、中间业务_个人_有效客户、中间业务_个人_快捷支付、中间业务_个人_电费代扣、中间业务_个人_水费代扣、中间业务_个人_华数费代扣、中间业务_个人_煤气费代扣、中间业务_个人_市民卡、中间业务_个人_理财业务、中间业务_个人_etc、BP_中间业务、TOTAL_BP_关联度 |
| 贷款特征 | 申请金额、BP_贷款额度、贷款用途、是否有经营佐证、BP_贷款用途、循环功能、BP_循环功能、抵质押类型、抵质押物三方所有、BP_抵押物 |
| 风险度分析 | 灰名单客户、本金逾期、利息逾期、信用卡逾期、BP_灰名单与逾期、TOTAL_BP_风险度 |
| 测算结果 | 浮动BP、测算利率 |
#### 企业客户模型输出 Tab 分类
| Tab 名称 | 字段内容 |
|---------|---------|
| 基本信息 | 客户内码、客户名称、证件类型、证件号码、基准利率 |
| 忠诚度分析 | 我行首贷客户、用信天数、BP_首贷、BP_贷龄、TOTAL_BP_忠诚度 |
| 贡献度分析 | 存款年日均、贷款年日均、派生率、TOTAL_BP_贡献度 |
| 关联度分析 | 中间业务_企业_企业互联、中间业务_企业_有效价值客户、中间业务_企业_国际业务、中间业务_企业_承兑、中间业务_企业_贴现、中间业务_企业_电费代扣、中间业务_企业_水费代扣、中间业务_企业_税务代扣、BP_中间业务、代发工资户数、存量贷款余额、BP_代发工资、TOTAL_BP_关联度 |
| 企业类别 | 净身企业、开立基本结算账户、省农担担保贷款、绿色贷款、科技型企业、BP_企业客户类别 |
| 贷款特征 | 贷款期限、BP_贷款期限、申请金额、BP_贷款额度、抵质押类型、抵质押物三方所有、BP_抵押物 |
| 风险度分析 | 灰名单客户、本金逾期、利息逾期、信用卡逾期、BP_灰名单与逾期、TOTAL_BP_风险度 |
| 测算结果 | 浮动BP、测算利率 |
## 影响范围
- 前端: `ruoyi-ui/src/views/loanPricing/workflow/detail.vue`
- API: 使用现有的 `GET /loanPricing/workflow/{serialNum}` 接口
## 设计考虑
1. **独立性**: 模型输出区域与流程基本信息分离,避免页面过于臃肿
2. **一致性**: 采用与现有详情页面相同的卡片 + Tab 布局风格
3. **响应式**: 保持移动端友好布局
4. **可扩展**: 预留未来可能新增的模型输出字段
## 替代方案
### 方案 A: 在现有详情对话框中添加 Tab (未采纳)
- **优点**: 集中展示,减少页面跳转
- **缺点**: 详情页改为独立页面后此方案不适用
### 方案 B: 新增独立页面展示模型输出 (未采纳)
- **优点**: 完全分离,职责清晰
- **缺点**: 增加用户操作步骤,需要额外的路由和菜单配置
### 方案 C: 在详情页下方新增卡片区域 (采纳)
- **优点**: 一次性获取所有信息,用户体验好,实现简单
- **缺点**: 单次页面内容较多(通过 Tab 解决)

View File

@@ -0,0 +1,63 @@
# loan-pricing-workflow-ui Spec Delta
## ADDED Requirements
### Requirement: 流程详情-模型输出展示
系统 SHALL 在流程详情页面中展示模型输出字段,根据客户类型显示对应的个人或企业模型输出数据。
#### Scenario: 查看个人客户模型输出
- **WHEN** 用户在流程详情页面查看个人客户的流程记录,且后端返回了 `modelRetailOutputFields` 数据
- **THEN** 系统在页面下方显示"模型输出"卡片区域,包含 7 个 Tab 标签页:
- **基本信息**: 客户内码、客户名称、证件类型、证件号码、基准利率
- **忠诚度分析**: 我行首贷客户、用信天数、客户年龄、BP_首贷、BP_贷龄、BP_年龄、TOTAL_BP_忠诚度
- **贡献度分析**: 存款年日均、贷款年日均、派生率、TOTAL_BP_贡献度
- **关联度分析**: 中间业务_个人_信用卡、中间业务_个人_一码通、中间业务_个人_丰收互联、中间业务_个人_有效客户、中间业务_个人_快捷支付、中间业务_个人_电费代扣、中间业务_个人_水费代扣、中间业务_个人_华数费代扣、中间业务_个人_煤气费代扣、中间业务_个人_市民卡、中间业务_个人_理财业务、中间业务_个人_etc、BP_中间业务、TOTAL_BP_关联度
- **贷款特征**: 申请金额、BP_贷款额度、贷款用途、是否有经营佐证、BP_贷款用途、循环功能、BP_循环功能、抵质押类型、抵质押物三方所有、BP_抵押物
- **风险度分析**: 灰名单客户、本金逾期、利息逾期、信用卡逾期、BP_灰名单与逾期、TOTAL_BP_风险度
- **测算结果**: 浮动BP、测算利率
#### Scenario: 查看企业客户模型输出
- **WHEN** 用户在流程详情页面查看企业客户的流程记录,且后端返回了 `modelCorpOutputFields` 数据
- **THEN** 系统在页面下方显示"模型输出"卡片区域,包含 8 个 Tab 标签页:
- **基本信息**: 客户内码、客户名称、证件类型、证件号码、基准利率
- **忠诚度分析**: 我行首贷客户、用信天数、BP_首贷、BP_贷龄、TOTAL_BP_忠诚度
- **贡献度分析**: 存款年日均、贷款年日均、派生率、TOTAL_BP_贡献度
- **关联度分析**: 中间业务_企业_企业互联、中间业务_企业_有效价值客户、中间业务_企业_国际业务、中间业务_企业_承兑、中间业务_企业_贴现、中间业务_企业_电费代扣、中间业务_企业_水费代扣、中间业务_企业_税务代扣、BP_中间业务、代发工资户数、存量贷款余额、BP_代发工资、TOTAL_BP_关联度
- **企业类别**: 净身企业、开立基本结算账户、省农担担保贷款、绿色贷款、科技型企业、BP_企业客户类别
- **贷款特征**: 贷款期限、BP_贷款期限、申请金额、BP_贷款额度、抵质押类型、抵质押物三方所有、BP_抵押物
- **风险度分析**: 灰名单客户、本金逾期、利息逾期、信用卡逾期、BP_灰名单与逾期、TOTAL_BP_风险度
- **测算结果**: 浮动BP、测算利率
#### Scenario: 无模型输出数据时隐藏展示区域
- **WHEN** 用户在流程详情页面查看流程记录,但 `modelRetailOutputFields``modelCorpOutputFields` 均为空
- **THEN** 系统不显示"模型输出"卡片区域
#### Scenario: 模型输出字段布尔值格式化
- **WHEN** 模型输出字段中布尔类型值(如 "true"/"false"
- **THEN** 系统将其格式化为中文"是"/"否"显示
#### Scenario: 模型输出字段空值处理
- **WHEN** 模型输出字段值为 null 或空字符串
- **THEN** 系统显示占位符"-"或空,不显示 "null" 或 "undefined"
#### Scenario: 模型输出区域布局一致性
- **WHEN** 用户查看流程详情页面
- **THEN** "模型输出"卡片区域的样式、Tab 样式、字体、间距与上方"流程详情"区域保持一致
#### Scenario: 模型输出区域响应式布局
- **WHEN** 用户在移动设备或小屏幕上查看流程详情页面
- **THEN** "模型输出"卡片区域正常显示Tab 标签页可正常切换,字段描述列表采用单列布局
## MODIFIED Requirements
### Requirement: 流程详情查看
系统 SHALL 提供流程详情查看功能,以独立页面形式展示完整的流程信息,包括模型输出数据。
#### Scenario: 查看流程详情
- **WHEN** 用户在流程列表页面且具有 `loanPricing:workflow:query` 权限,点击列表中某条记录的"查看"按钮
- **THEN** 系统跳转至流程详情页面 `/loanPricing/workflow/detail/:serialNum`,展示:
- **左侧摘要卡片**: 业务方流水号、客户名称、客户类型、申请金额、贷款利率、担保方式
- **右侧详情标签页**: 基本信息页签、业务信息页签、中间业务标识页签、企业标识页签、其他信息页签
- **下方模型输出卡片**: 当存在模型输出数据时显示,根据客户类型展示对应的个人或企业模型输出字段

View File

@@ -0,0 +1,53 @@
# 任务列表: 模型输出展示功能
## 实施顺序
### 1. 前端页面结构调整
- [x] 在 detail.vue 中新增模型输出展示区域el-card
- [x] 添加条件渲染逻辑:仅当模型输出数据存在时显示
- [x] 添加客户类型判断逻辑:个人/企业显示不同字段
- [x] 抽离模型输出组件 ModelOutputDisplay.vue
### 2. 页面布局调整
- [x] 将模型输出组件放在关键信息右侧(三栏布局)
- [x] 调整响应式布局支持不同屏幕尺寸
### 3. 个人客户模型输出组件
- [x] 创建个人模型输出 Tab 结构7 个 Tab
- [x] 实现"基本信息"Tab 字段展示5 个字段)
- [x] 实现"忠诚度分析"Tab 字段展示7 个字段)
- [x] 实现"贡献度分析"Tab 字段展示4 个字段)
- [x] 实现"关联度分析"Tab 字段展示14 个字段)
- [x] 实现"贷款特征"Tab 字段展示10 个字段)
- [x] 实现"风险度分析"Tab 字段展示7 个字段)
- [x] 实现"测算结果"Tab 字段展示2 个字段)
### 4. 企业客户模型输出组件
- [x] 创建企业模型输出 Tab 结构8 个 Tab
- [x] 实现"基本信息"Tab 字段展示5 个字段)
- [x] 实现"忠诚度分析"Tab 字段展示6 个字段)
- [x] 实现"贡献度分析"Tab 字段展示4 个字段)
- [x] 实现"关联度分析"Tab 字段展示13 个字段)
- [x] 实现"企业类别"Tab 字段展示6 个字段)
- [x] 实现"贷款特征"Tab 字段展示7 个字段)
- [x] 实现"风险度分析"Tab 字段展示7 个字段)
- [x] 实现"测算结果"Tab 字段展示2 个字段)
### 5. 数据适配
- [x] 修改 API 响应数据解析逻辑,支持 `LoanPricingWorkflowVO` 结构
- [x] 添加模型输出字段的数据绑定
- [x] 添加布尔值字段的格式化true/false → 是/否)
- [x] 添加空值处理逻辑
### 6. 样式调整
- [x] 保持与现有详情页面一致的卡片样式
- [x] 保持 Tab 样式一致性
- [x] 确保响应式布局在移动端正常显示
- [x] 调整卡片间距
### 7. 测试验证
- [ ] 测试个人客户数据展示
- [ ] 测试企业客户数据展示
- [ ] 测试无模型输出数据时的页面表现
- [ ] 测试响应式布局
- [ ] 测试各 Tab 切换交互

View File

@@ -18,16 +18,16 @@ public class MyMetaHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createBy", SecurityUtils.getUsername(), metaObject);
this.setFieldValByName("createBy", SecurityUtils.getLoginUser().getUser().getNickName() + '-'+ SecurityUtils.getUsername(), metaObject);
this.setFieldValByName("createTime", new Date(), metaObject);
this.setFieldValByName("updateBy", SecurityUtils.getUsername(), metaObject);
this.setFieldValByName("updateBy", SecurityUtils.getLoginUser().getUser().getNickName() + '-'+ SecurityUtils.getUsername(), metaObject);
this.setFieldValByName("updateTime", new Date(), metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateBy", SecurityUtils.getUsername(), metaObject);
this.setFieldValByName("updateBy", SecurityUtils.getLoginUser().getUser().getNickName() + '-'+ SecurityUtils.getUsername(), metaObject);
this.setFieldValByName("updateTime", new Date(), metaObject);
}
}

View File

@@ -0,0 +1,306 @@
<template>
<el-card class="model-output-card" v-if="custType && (retailOutput || corpOutput)">
<div slot="header" class="card-header">
<span class="card-title">模型输出</span>
</div>
<el-tabs v-model="activeTab">
<!-- 个人客户模型输出 -->
<template v-if="custType === '个人' && retailOutput">
<!-- 基本信息 -->
<el-tab-pane label="基本信息" name="retail-basic">
<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">{{ retailOutput.baseLoanRate || '-' }}</span> %</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<!-- 忠诚度分析 -->
<el-tab-pane label="忠诚度分析" name="retail-loyalty">
<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>
</el-tab-pane>
<!-- 贡献度分析 -->
<el-tab-pane label="贡献度分析" name="retail-contribution">
<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="派生率">{{ retailOutput.derivationRate || '-' }}</el-descriptions-item>
<el-descriptions-item label="TOTAL_BP_贡献度"><span class="total-bp-value">{{ retailOutput.totalBpContribution || '-' }}</span></el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<!-- 关联度分析 -->
<el-tab-pane label="关联度分析" name="retail-relevance">
<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.totoalBpRelevance || '-' }}</span></el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<!-- 贷款特征 -->
<el-tab-pane label="贷款特征" name="retail-loan">
<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>
</el-tab-pane>
<!-- 风险度分析 -->
<el-tab-pane label="风险度分析" name="retail-risk">
<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.totoalBpRisk || '-' }}</span></el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<!-- 测算结果 -->
<el-tab-pane label="测算结果" name="retail-result">
<el-descriptions :column="2" border size="small">
<el-descriptions-item label="浮动BP"><span class="total-bp-value">{{ retailOutput.totalBp || '-' }}</span></el-descriptions-item>
<el-descriptions-item label="测算利率"><span class="calculate-rate">{{ retailOutput.calculateRate || '-' }}</span> %</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
</template>
<!-- 企业客户模型输出 -->
<template v-else-if="custType === '企业' && corpOutput">
<!-- 基本信息 -->
<el-tab-pane label="基本信息" name="corp-basic">
<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">{{ corpOutput.baseLoanRate || '-' }}</span> %</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<!-- 忠诚度分析 -->
<el-tab-pane label="忠诚度分析" name="corp-loyalty">
<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>
</el-tab-pane>
<!-- 贡献度分析 -->
<el-tab-pane label="贡献度分析" name="corp-contribution">
<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="派生率">{{ corpOutput.derivationRate || '-' }}</el-descriptions-item>
<el-descriptions-item label="TOTAL_BP_贡献度"><span class="total-bp-value">{{ corpOutput.totalBpContribution || '-' }}</span></el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<!-- 关联度分析 -->
<el-tab-pane label="关联度分析" name="corp-relevance">
<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="中间业务_企业_税务代扣">{{ formatBoolean(corpOutput.midEntTax) }}</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.totoalBpRelevance || '-' }}</span></el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<!-- 企业类别 -->
<el-tab-pane label="企业类别" name="corp-category">
<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.isAgriGuar) }}</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="BP_企业客户类别"><span class="bp-value">{{ corpOutput.bpEntType || '-' }}</span></el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<!-- 贷款特征 -->
<el-tab-pane label="贷款特征" name="corp-loan">
<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>
</el-tab-pane>
<!-- 风险度分析 -->
<el-tab-pane label="风险度分析" name="corp-risk">
<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="信用卡逾期">{{ formatBoolean(corpOutput.cardOverdue) }}</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.totoalBpRisk || '-' }}</span></el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<!-- 测算结果 -->
<el-tab-pane label="测算结果" name="corp-result">
<el-descriptions :column="2" border size="small">
<el-descriptions-item label="浮动BP"><span class="total-bp-value">{{ corpOutput.totalBp || '-' }}</span></el-descriptions-item>
<el-descriptions-item label="测算利率"><span class="calculate-rate">{{ corpOutput.calculateRate || '-' }}</span> %</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
</template>
</el-tabs>
</el-card>
</template>
<script>
export default {
name: "ModelOutputDisplay",
props: {
custType: {
type: String,
default: null
},
retailOutput: {
type: Object,
default: null
},
corpOutput: {
type: Object,
default: null
}
},
data() {
return {
activeTab: ''
}
},
watch: {
custType: {
immediate: true,
handler(val) {
// 根据客户类型设置默认 tab
if (val === '个人') {
this.activeTab = 'retail-basic'
} else if (val === '企业') {
this.activeTab = 'corp-basic'
}
}
}
},
methods: {
/** 格式化布尔值为中文 */
formatBoolean(value) {
if (value === 'true' || value === true) return '是'
if (value === 'false' || value === false) return '否'
return value || '-'
},
/** 格式化贷款用途 */
formatLoanPurpose(value) {
if (value === 'consumer') return '消费贷款'
if (value === 'business') return '经营贷款'
return value || '-'
}
}
}
</script>
<style lang="scss" scoped>
.model-output-card {
::v-deep .el-card__header {
padding: 16px 20px;
background-color: #fafafa;
border-bottom: 1px solid #ebeef5;
}
.card-header {
display: flex;
align-items: center;
.card-title {
font-size: 16px;
font-weight: 500;
color: #303133;
}
}
::v-deep .el-card__body {
padding: 20px;
}
::v-deep .el-tabs__header {
margin-bottom: 20px;
}
// BP 值样式
.bp-value {
color: #409eff;
font-weight: 500;
}
// TOTAL_BP 样式
.total-bp-value {
color: #e6a23c;
font-weight: 600;
}
// 测算利率高亮样式
.calculate-rate {
color: #f56c6c;
font-weight: 600;
font-size: 16px;
}
// 利率值样式
.rate-value {
color: #67c23a;
font-weight: 500;
}
}
</style>

View File

@@ -6,97 +6,121 @@
<el-button icon="el-icon-back" size="small" @click="goBack">返回</el-button>
</div>
<!-- 两栏布局 -->
<el-row :gutter="20" v-if="!loading && detail">
<!-- 左侧摘要卡片30% -->
<el-col :xs="24" :sm="24" :md="8" :lg="7" :xl="6">
<!-- 两栏布局左侧关键信息 + 右侧流程详情+模型输出 -->
<div v-if="!loading && workflowDetail" class="detail-layout">
<!-- 左侧关键信息卡片 -->
<div class="left-panel">
<el-card class="summary-card">
<div slot="header" class="card-header">
<span class="card-title">关键信息</span>
</div>
<el-descriptions :column="1" direction="vertical" border>
<el-descriptions-item label="业务方流水号">{{ detail.serialNum }}</el-descriptions-item>
<el-descriptions-item label="客户名称">{{ detail.custName }}</el-descriptions-item>
<el-descriptions-item label="客户类型">{{ detail.custType }}</el-descriptions-item>
<el-descriptions-item label="申请金额">{{ detail.applyAmt }} </el-descriptions-item>
<el-descriptions-item label="贷款利率">{{ detail.loanRate }} %</el-descriptions-item>
<el-descriptions-item label="担保方式">{{ detail.guarType }}</el-descriptions-item>
<el-descriptions-item label="业务方流水号">{{ workflowDetail.serialNum }}</el-descriptions-item>
<el-descriptions-item label="客户名称">{{ workflowDetail.custName }}</el-descriptions-item>
<el-descriptions-item label="客户类型">{{ workflowDetail.custType }}</el-descriptions-item>
<el-descriptions-item label="申请金额">{{ workflowDetail.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>
</el-descriptions>
</el-card>
</el-col>
</div>
<!-- 右侧详情标签页70% -->
<el-col :xs="24" :sm="24" :md="16" :lg="17" :xl="18">
<!-- 右侧面板包含流程详情和模型输出 -->
<div class="right-panel">
<!-- 流程详情卡片 -->
<el-card class="detail-card">
<div slot="header" class="card-header">
<span class="card-title">流程详情</span>
</div>
<el-tabs v-model="activeTab">
<!-- 基本信息 -->
<el-tab-pane label="基本信息" name="basic">
<el-descriptions :column="2" border>
<el-descriptions-item label="机构编码">{{ detail.orgCode }}</el-descriptions-item>
<el-descriptions-item label="运行模式">{{ detail.runType }}</el-descriptions-item>
<el-descriptions-item label="客户内码">{{ detail.custIsn }}</el-descriptions-item>
<el-descriptions-item label="证件类型">{{ detail.idType }}</el-descriptions-item>
<el-descriptions-item label="机构编码">{{ workflowDetail.orgCode }}</el-descriptions-item>
<el-descriptions-item label="运行模式">{{ workflowDetail.runType }}</el-descriptions-item>
<el-descriptions-item label="客户内码">{{ workflowDetail.custIsn }}</el-descriptions-item>
<el-descriptions-item label="证件类型">{{ workflowDetail.idType }}</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<!-- 业务信息 -->
<el-tab-pane label="业务信息" name="business">
<el-descriptions :column="2" border>
<el-descriptions-item label="贷款用途">{{ detail.loanPurpose === 'consumer' ? '消费贷款' : detail.loanPurpose === 'business' ? '经营贷款' : detail.loanPurpose }}</el-descriptions-item>
<el-descriptions-item label="是否有经营佐证">{{ detail.bizProof === 'true' ? '是' : '否' }}</el-descriptions-item>
<el-descriptions-item label="抵质押类型">{{ detail.collType }}</el-descriptions-item>
<el-descriptions-item label="抵质押物三方所有">{{ detail.collThirdParty === 'true' ? '是' : '否' }}</el-descriptions-item>
<el-descriptions-item label="贷款用途">{{ formatLoanPurpose(workflowDetail.loanPurpose) }}</el-descriptions-item>
<el-descriptions-item label="是否有经营佐证">{{ formatBoolean(workflowDetail.bizProof) }}</el-descriptions-item>
<el-descriptions-item label="抵质押类型">{{ workflowDetail.collType }}</el-descriptions-item>
<el-descriptions-item label="抵质押物三方所有">{{ formatBoolean(workflowDetail.collThirdParty) }}</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<!-- 中间业务标识 -->
<el-tab-pane label="中间业务标识" name="mid">
<el-descriptions :column="2" border>
<el-descriptions-item label="个人快捷支付">{{ detail.midPerQuickPay === 'true' ? '是' : '否' }}</el-descriptions-item>
<el-descriptions-item label="个人电费代扣">{{ detail.midPerEleDdc === 'true' ? '是' : '否' }}</el-descriptions-item>
<el-descriptions-item label="企业电费代扣">{{ detail.midEntEleDdc === 'true' ? '是' : '否' }}</el-descriptions-item>
<el-descriptions-item label="企业水费代扣">{{ detail.midEntWaterDdc === 'true' ? '是' : '否' }}</el-descriptions-item>
<el-descriptions-item label="个人快捷支付">{{ formatBoolean(workflowDetail.midPerQuickPay) }}</el-descriptions-item>
<el-descriptions-item label="个人电费代扣">{{ formatBoolean(workflowDetail.midPerEleDdc) }}</el-descriptions-item>
<el-descriptions-item label="企业电费代扣">{{ formatBoolean(workflowDetail.midEntEleDdc) }}</el-descriptions-item>
<el-descriptions-item label="企业水费代扣">{{ formatBoolean(workflowDetail.midEntWaterDdc) }}</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<!-- 企业标识 -->
<el-tab-pane label="企业标识" name="ent">
<el-descriptions :column="2" border>
<el-descriptions-item label="净身企业">{{ detail.isCleanEnt === 'true' ? '是' : '否' }}</el-descriptions-item>
<el-descriptions-item label="开立基本结算账户">{{ detail.hasSettleAcct === 'true' ? '是' : '否' }}</el-descriptions-item>
<el-descriptions-item label="制造业企业">{{ detail.isManufacturing === 'true' ? '是' : '否' }}</el-descriptions-item>
<el-descriptions-item label="省农担担保贷款">{{ detail.isAgriGuar === 'true' ? '是' : '否' }}</el-descriptions-item>
<el-descriptions-item label="纳税信用等级A级">{{ detail.isTaxA === 'true' ? '是' : '否' }}</el-descriptions-item>
<el-descriptions-item label="县级及以上农业龙头企业">{{ detail.isAgriLeading === 'true' ? '是' : '否' }}</el-descriptions-item>
<el-descriptions-item label="普惠小微借款人">{{ detail.isInclusiveFinance === 'true' ? '是' : '否' }}</el-descriptions-item>
<el-descriptions-item label="净身企业">{{ formatBoolean(workflowDetail.isCleanEnt) }}</el-descriptions-item>
<el-descriptions-item label="开立基本结算账户">{{ formatBoolean(workflowDetail.hasSettleAcct) }}</el-descriptions-item>
<el-descriptions-item label="制造业企业">{{ formatBoolean(workflowDetail.isManufacturing) }}</el-descriptions-item>
<el-descriptions-item label="省农担担保贷款">{{ formatBoolean(workflowDetail.isAgriGuar) }}</el-descriptions-item>
<el-descriptions-item label="纳税信用等级A级">{{ formatBoolean(workflowDetail.isTaxA) }}</el-descriptions-item>
<el-descriptions-item label="县级及以上农业龙头企业">{{ formatBoolean(workflowDetail.isAgriLeading) }}</el-descriptions-item>
<el-descriptions-item label="普惠小微借款人">{{ formatBoolean(workflowDetail.isInclusiveFinance) }}</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<!-- 其他信息 -->
<el-tab-pane label="其他信息" name="other">
<el-descriptions :column="2" border>
<el-descriptions-item label="创建时间">{{ detail.createTime }}</el-descriptions-item>
<el-descriptions-item label="创建者">{{ detail.createBy }}</el-descriptions-item>
<el-descriptions-item label="更新时间">{{ detail.updateTime }}</el-descriptions-item>
<el-descriptions-item label="更新者">{{ detail.updateBy }}</el-descriptions-item>
<el-descriptions-item label="创建时间">{{ workflowDetail.createTime }}</el-descriptions-item>
<el-descriptions-item label="创建者">{{ workflowDetail.createBy }}</el-descriptions-item>
<el-descriptions-item label="更新时间">{{ workflowDetail.updateTime }}</el-descriptions-item>
<el-descriptions-item label="更新者">{{ workflowDetail.updateBy }}</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
</el-tabs>
</el-card>
</el-col>
</el-row>
<!-- 模型输出卡片 -->
<ModelOutputDisplay
:cust-type="workflowDetail.custType"
:retail-output="retailOutput"
:corp-output="corpOutput"
/>
</div>
</div>
</div>
</template>
<script>
import { getWorkflow } from "@/api/loanPricing/workflow"
import ModelOutputDisplay from "./components/ModelOutputDisplay.vue"
export default {
name: "LoanPricingWorkflowDetail",
components: {
ModelOutputDisplay
},
data() {
return {
loading: true,
detail: null,
workflowDetail: null,
retailOutput: null,
corpOutput: null,
activeTab: 'basic'
}
},
@@ -114,7 +138,10 @@ export default {
}
getWorkflow(serialNum).then(response => {
this.detail = response.data
// 适配新的 API 响应结构 LoanPricingWorkflowVO
this.workflowDetail = response.data.loanPricingWorkflow
this.retailOutput = response.data.modelRetailOutputFields
this.corpOutput = response.data.modelCorpOutputFields
this.loading = false
}).catch(error => {
this.$modal.msgError("获取流程详情失败:" + (error.message || "未知错误"))
@@ -124,6 +151,45 @@ export default {
/** 返回上一页 */
goBack() {
this.$router.go(-1)
},
/** 格式化布尔值为中文 */
formatBoolean(value) {
if (value === 'true' || value === true) return '是'
if (value === 'false' || value === false) return '否'
return value || '-'
},
/** 格式化贷款用途 */
formatLoanPurpose(value) {
if (value === 'consumer') return '消费贷款'
if (value === 'business') return '经营贷款'
return value || '-'
},
/** 获取基准利率 */
getBaseLoanRate() {
if (this.workflowDetail.custType === '个人' && this.retailOutput) {
return this.retailOutput.baseLoanRate || '-'
} else if (this.workflowDetail.custType === '企业' && this.corpOutput) {
return this.corpOutput.baseLoanRate || '-'
}
return '-'
},
/** 获取浮动BP */
getTotalBp() {
if (this.workflowDetail.custType === '个人' && this.retailOutput) {
return this.retailOutput.totalBp || '-'
} else if (this.workflowDetail.custType === '企业' && this.corpOutput) {
return this.corpOutput.totalBp || '-'
}
return '-'
},
/** 获取测算利率 */
getCalculateRate() {
if (this.workflowDetail.custType === '个人' && this.retailOutput) {
return this.retailOutput.calculateRate || '-'
} else if (this.workflowDetail.custType === '企业' && this.corpOutput) {
return this.corpOutput.calculateRate || '-'
}
return '-'
}
}
}
@@ -146,47 +212,110 @@ export default {
}
}
.summary-card {
margin-bottom: 20px;
// 两栏布局
.detail-layout {
display: flex;
gap: 20px;
align-items: flex-start;
::v-deep .el-card__header {
padding: 16px 20px;
background-color: #fafafa;
border-bottom: 1px solid #ebeef5;
}
// 左侧关键信息卡片 (固定宽度)
.left-panel {
flex: 0 0 280px;
max-width: 280px;
.card-header {
display: flex;
align-items: center;
.summary-card {
::v-deep .el-card__header {
padding: 16px 20px;
background-color: #fafafa;
border-bottom: 1px solid #ebeef5;
}
.card-title {
font-size: 16px;
font-weight: 500;
color: #303133;
.card-header {
display: flex;
align-items: center;
.card-title {
font-size: 16px;
font-weight: 500;
color: #303133;
}
}
::v-deep .el-card__body {
padding: 16px;
}
// 利率值样式
.rate-value {
color: #67c23a;
font-weight: 500;
}
// TOTAL_BP 样式
.total-bp-value {
color: #e6a23c;
font-weight: 600;
}
// 测算利率高亮样式
.calculate-rate {
color: #f56c6c;
font-weight: 600;
font-size: 16px;
}
}
}
::v-deep .el-card__body {
padding: 16px;
}
}
// 右侧面板:包含流程详情和模型输出
.right-panel {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 20px;
.detail-card {
::v-deep .el-card__body {
padding: 20px;
}
.detail-card {
::v-deep .el-card__header {
padding: 16px 20px;
background-color: #fafafa;
border-bottom: 1px solid #ebeef5;
}
::v-deep .el-tabs__header {
margin-bottom: 20px;
.card-header {
display: flex;
align-items: center;
.card-title {
font-size: 16px;
font-weight: 500;
color: #303133;
}
}
::v-deep .el-card__body {
padding: 20px;
}
::v-deep .el-tabs__header {
margin-bottom: 20px;
}
}
}
}
}
// 响应式:小屏幕下左侧卡片在顶部显示
@media screen and (max-width: 767px) {
// 响应式布局
@media screen and (max-width: 992px) {
.workflow-detail-container {
.summary-card {
margin-bottom: 20px;
.detail-layout {
// 切换为单列垂直布局
flex-direction: column;
.left-panel,
.right-panel {
flex: 1 1 100%;
max-width: 100%;
}
}
}
}