输入表单布局

This commit is contained in:
wkc
2026-01-21 09:32:22 +08:00
parent 3624198aa6
commit c4a05e1338
6 changed files with 428 additions and 168 deletions

View File

@@ -0,0 +1,80 @@
# Design: 移除流程创建弹窗的 Tab 栏布局
## Current Implementation
当前 `WorkflowCreateDialog.vue` 使用 `el-tabs` 组件组织表单字段:
```vue
<el-tabs v-model="activeTab">
<el-tab-pane label="基本信息" name="basic">
<!-- 客户内码客户名称客户类型证件类型 -->
</el-tab-pane>
<el-tab-pane label="贷款信息" name="loan">
<!-- 申请金额贷款利率担保方式贷款用途抵质押类型是否有经营佐证抵质押物三方所有 -->
</el-tab-pane>
<el-tab-pane label="中间业务标识" name="mid">
<!-- 个人快捷支付个人电费代扣企业电费代扣企业水费代扣 -->
</el-tab-pane>
<el-tab-pane label="企业标识" name="ent">
<!-- 净身企业开立基本结算账户制造业企业省农担担保贷款纳税信用等级A级县级及以上农业龙头企业普惠小微借款人 -->
</el-tab-pane>
</el-tabs>
```
## Proposed Implementation
使用 Element UI 的 `el-divider` 组件作为分组标题,移除 `el-tabs``el-tab-pane`
```vue
<el-form ref="form" :model="form" :rules="rules" label-width="140px">
<!-- 基本信息 -->
<el-divider content-position="left">基本信息</el-divider>
<el-row>
<el-col :span="12">
<el-form-item label="客户内码" prop="custIsn">
<el-input v-model="form.custIsn" placeholder="请输入客户内码" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="客户名称" prop="custName">
<el-input v-model="form.custName" placeholder="请输入客户名称" />
</el-form-item>
</el-col>
</el-row>
<!-- ... 其他基本信息字段 ... -->
<!-- 贷款信息 -->
<el-divider content-position="left">贷款信息</el-divider>
<!-- ... 贷款信息字段 ... -->
<!-- 中间业务标识 -->
<el-divider content-position="left">中间业务标识</el-divider>
<!-- ... 中间业务标识字段 ... -->
<!-- 企业标识 -->
<el-divider content-position="left">企业标识</el-divider>
<!-- ... 企业标识字段 ... -->
</el-form>
```
同时需要移除 `data()` 中的 `activeTab` 属性。
## CSS Styling
`el-divider` 添加适当的外边距,确保分组标题与表单字段之间有清晰的视觉分隔:
```css
.el-divider {
margin: 16px 0 20px 0;
font-weight: bold;
}
```
或使用 `<style scoped>` 在组件内定义。
## Rationale
1. **单一表单布局**:所有字段在同一页面可见,用户可以快速浏览和填写
2. **分组标题**:使用 `el-divider``content-position` 属性显示分组标题,保持清晰的视觉层次
3. **滚动支持**:对话框内容区域可滚动,支持大量字段的显示
4. **保持验证逻辑**:不需要修改表单验证逻辑,`el-form` 的验证机制仍然有效

View File

@@ -0,0 +1,43 @@
# Proposal: 移除流程创建弹窗的 Tab 栏布局
## Summary
修改 `WorkflowCreateDialog.vue` 组件,将当前使用 `el-tabs` 分组的多 tab 栏布局改为单一表单的垂直布局,使用分组标题(如 Element UI 的 `el-divider` 或自定义标题)来区分不同的字段区域。
## Motivation
当前实现使用 `el-tabs` 将表单字段分为四个标签页(基本信息、贷款信息、中间业务标识、企业标识),存在以下问题:
1. **用户体验不佳**:用户需要在多个 tab 之间切换才能完成表单填写,增加了操作步骤
2. **表单可见性差**:用户无法一次性看到所有需要填写的字段,可能遗漏某些选项
3. **确认验证困难**:点击"确定"时,用户可能看不到其他 tab 中必填字段的验证提示
## Proposed Solution
移除 `el-tabs` 组件,改用单一表单布局,使用视觉分隔符或分组标题来组织字段:
- **基本信息**:使用 `el-divider` 或分组标题
- **贷款信息**:使用 `el-divider` 或分组标题
- **中间业务标识**:使用 `el-divider` 或分组标题
- **企业标识**:使用 `el-divider` 或分组标题
- **抵质押信息**:整合到"贷款信息"分组下或单独分组
所有字段垂直排列,用户可以滚动查看和填写。
## Alternatives Considered
1. **保持 tab 栏但优化布局**:不解决用户体验问题
2. **使用手风琴折叠面板**:仍需要展开/收起操作,不如单一表单直观
3. **使用分步表单Steps**:增加了操作步骤,不适合简单的表单填写场景
## Impact
- **Scope**: 仅影响 `WorkflowCreateDialog.vue` 组件的 UI 布局
- **Breaking Changes**: 无UI 改进,功能不变)
- **Dependencies**: 无新增依赖
## Related Changes
- Modifies: `loan-pricing-workflow-ui` spec (Requirement: 流程创建)
- Related Files:
- `ruoyi-ui/src/views/loanPricing/workflow/components/WorkflowCreateDialog.vue`

View File

@@ -0,0 +1,36 @@
# loan-pricing-workflow-ui Spec Delta
## MODIFIED Requirements
### Requirement: 流程创建
系统 SHALL 提供创建新利率定价流程的功能,通过表单对话框收集必要信息。
#### Scenario: 打开创建表单
- **WHEN** 用户在流程列表页面且具有 `loanPricing:workflow:create` 权限,点击"新增"按钮
- **THEN** 系统弹出创建流程表单对话框,在单一表单页面中垂直显示所有必填和可选字段,使用分组标题区分不同的字段区域
#### Scenario: 表单字段显示
- **WHEN** 用户打开创建流程表单对话框
- **THEN** 系统在单一表单中显示以下字段分组,使用分隔符或分组标题区分:
- **基本信息**分组:客户内码(必填)、客户名称、客户类型(必填,下拉选择:个人/企业)、证件类型
- **贷款信息**分组:申请金额(必填)、贷款利率(必填)、担保方式(必填,下拉选择:信用/保证/抵押/质押、贷款用途下拉选择consumer/business、抵质押类型下拉选择一线/一类/二类)、是否有经营佐证(开关)、抵质押物三方所有(开关)
- **中间业务标识**分组:个人快捷支付(开关)、个人电费代扣(开关)、企业电费代扣(开关)、企业水费代扣(开关)
- **企业标识**分组净身企业开关、开立基本结算账户开关、制造业企业开关、省农担担保贷款开关、纳税信用等级A级开关、县级及以上农业龙头企业开关、普惠小微借款人开关
- **固定字段**机构编码隐藏固定值931000、运行模式隐藏固定值1
#### Scenario: 表单验证
- **WHEN** 用户填写表单并点击确定按钮
- **THEN** 系统在同一表单页面中验证必填字段:客户内码、客户类型、担保方式、申请金额、贷款利率,如有缺失则在对应字段位置显示错误提示
#### Scenario: 提交创建成功
- **WHEN** 用户填写完必填字段并点击确定按钮,后端返回成功响应
- **THEN** 系统关闭对话框,显示成功提示消息,刷新列表数据
#### Scenario: 取消创建
- **WHEN** 用户点击取消按钮或对话框关闭按钮
- **THEN** 系统关闭对话框,不保存数据,不刷新列表
#### Scenario: 新增按钮权限控制
- **WHEN** 用户不具有 `loanPricing:workflow:create` 权限
- **THEN** 系统不显示"新增"按钮

View File

@@ -0,0 +1,21 @@
# Tasks
1. **修改 WorkflowCreateDialog.vue 组件布局**
- 移除 `el-tabs``el-tab-pane` 组件
- 添加分组标题/分隔符来区分字段区域
- 保持所有表单字段和验证规则不变
- 验证表单提交功能正常工作
2. **测试验证**
- 测试所有必填字段的验证是否正常
- 测试表单提交功能
- 测试取消和关闭对话框功能
- 确认在不同屏幕尺寸下的显示效果
## Validation Criteria
- [x] 移除 tab 栏,所有字段在单一表单中可见
- [x] 使用分组标题/分隔符清晰区分字段区域
- [x] 表单验证功能正常
- [x] 表单提交功能正常
- [x] 取消和关闭功能正常

View File

@@ -0,0 +1,79 @@
package com.ruoyi.loanpricing.service;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.loanratepricing.domain.RatePricingProperties;
import com.ruoyi.loanratepricing.domain.dto.ModelInvokeDTO;
import com.ruoyi.loanratepricing.domain.entity.ModelOutputFields;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* @Author 吴凯程
* @Date 2025/12/11
**/
@Service
@Slf4j
public class ModelService {
@Resource
private RatePricingProperties ratePricingProperties;
@Resource
private RedisCache redisCache;
public ModelOutputFields invokeModel(ModelInvokeDTO modelInvokeDTO) {
Map<String, String> requestBody = entityToMap(modelInvokeDTO);
JSONObject response = HttpUtils.doPostFormUrlEncoded(ratePricingProperties.getModelUrl(), requestBody, null, JSONObject.class);
log.info("------------------->调用模型返回结果:" + JSON.toJSONString(response));
if(Objects.nonNull(response) && response.containsKey("code") && response.getInteger("code") == 10000){
JSONObject mappingOutputFields = response.getJSONObject("data").getJSONObject("mappingOutputFields");
return JSON.parseObject(mappingOutputFields.toJSONString(), ModelOutputFields.class);
}else{
log.error("------------------->调用模型失败,失败原因为:" + response.getString("message"));
throw new ServiceException("调用模型失败");
}
}
/**
* 使用FastJSON将实体类转换为Map<String, String>
* @param obj 待转换的实体类对象
* @return 转换后的Map
*/
public static Map<String, String> entityToMap(Object obj) {
if (obj == null) {
return null;
}
// 先转为JSON字符串再转换为指定类型的Map
String jsonStr = JSON.toJSONString(obj);
return JSON.parseObject(jsonStr, new TypeReference<Map<String, String>>() {});
}
private void replaceIndicatorToVariableName(JSONObject jsonObject) {
List<SysDictData> variableNameList = redisCache.getCacheObject("sys_dict:model_indicator_metric");
variableNameList.forEach(sysDictData -> {
if (jsonObject.containsKey(sysDictData.getDictLabel())) {
jsonObject.put(sysDictData.getDictValue(), jsonObject.get(sysDictData.getDictLabel()));
jsonObject.remove(sysDictData.getDictLabel());
}
});
}
}

View File

@@ -1,175 +1,169 @@
<template>
<el-dialog title="新增利率定价流程" :visible.sync="dialogVisible" width="900px" append-to-body @close="handleClose">
<el-form ref="form" :model="form" :rules="rules" label-width="140px">
<el-tabs v-model="activeTab">
<!-- 基本信息 -->
<el-tab-pane label="基本信息" name="basic">
<el-row>
<el-col :span="12">
<el-form-item label="客户内码" prop="custIsn">
<el-input v-model="form.custIsn" placeholder="请输入客户内码" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="客户名称" prop="custName">
<el-input v-model="form.custName" placeholder="请输入客户名称" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="客户类型" prop="custType">
<el-select v-model="form.custType" placeholder="请选择客户类型" style="width: 100%">
<el-option label="个人" value="个人" />
<el-option label="企业" value="企业" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="证件类型" prop="idType">
<el-select v-model="form.idType" placeholder="请选择证件类型" style="width: 100%">
<el-option label="身份证" value="身份证" />
<el-option label="统一社会信用代码" value="统一社会信用代码" />
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-tab-pane>
<el-form ref="form" :model="form" :rules="rules" label-width="140px" class="workflow-create-form">
<!-- 基本信息 -->
<el-divider content-position="left">基本信息</el-divider>
<el-row>
<el-col :span="12">
<el-form-item label="客户内码" prop="custIsn">
<el-input v-model="form.custIsn" placeholder="请输入客户内码" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="客户名称" prop="custName">
<el-input v-model="form.custName" placeholder="请输入客户名称" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="客户类型" prop="custType">
<el-select v-model="form.custType" placeholder="请选择客户类型" style="width: 100%">
<el-option label="个人" value="个人" />
<el-option label="企业" value="企业" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="证件类型" prop="idType">
<el-select v-model="form.idType" placeholder="请选择证件类型" style="width: 100%">
<el-option label="身份证" value="身份证" />
<el-option label="统一社会信用代码" value="统一社会信用代码" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<!-- 贷款信息 -->
<el-tab-pane label="贷款信息" name="loan">
<el-row>
<el-col :span="12">
<el-form-item label="申请金额(元)" prop="applyAmt">
<el-input v-model="form.applyAmt" placeholder="请输入申请金额" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="贷款利率(%)" prop="loanRate">
<el-input v-model="form.loanRate" placeholder="请输入贷款利率" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="担保方式" prop="guarType">
<el-select v-model="form.guarType" placeholder="请选择担保方式" style="width: 100%">
<el-option label="信用" value="信用" />
<el-option label="保证" value="保证" />
<el-option label="抵押" value="抵押" />
<el-option label="质押" value="质押" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="贷款用途" prop="loanPurpose">
<el-select v-model="form.loanPurpose" placeholder="请选择贷款用途" style="width: 100%">
<el-option label="消费贷款" value="consumer" />
<el-option label="经营贷款" value="business" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="抵质押类型" prop="collType">
<el-select v-model="form.collType" placeholder="请选择抵质押类型" style="width: 100%">
<el-option label="一线" value="一线" />
<el-option label="一类" value="一类" />
<el-option label="二类" value="二类" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="是否有经营佐证">
<el-switch v-model="form.bizProofActive" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="抵质押物三方所有">
<el-switch v-model="form.collThirdPartyActive" />
</el-form-item>
</el-col>
</el-row>
</el-tab-pane>
<!-- 贷款信息 -->
<el-divider content-position="left">贷款信息</el-divider>
<el-row>
<el-col :span="12">
<el-form-item label="申请金额(元)" prop="applyAmt">
<el-input v-model="form.applyAmt" placeholder="请输入申请金额" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="贷款利率(%)" prop="loanRate">
<el-input v-model="form.loanRate" placeholder="请输入贷款利率" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="担保方式" prop="guarType">
<el-select v-model="form.guarType" placeholder="请选择担保方式" style="width: 100%">
<el-option label="信用" value="信用" />
<el-option label="保证" value="保证" />
<el-option label="抵押" value="抵押" />
<el-option label="质押" value="质押" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="贷款用途" prop="loanPurpose">
<el-select v-model="form.loanPurpose" placeholder="请选择贷款用途" style="width: 100%">
<el-option label="消费贷款" value="consumer" />
<el-option label="经营贷款" value="business" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="抵质押类型" prop="collType">
<el-select v-model="form.collType" placeholder="请选择抵质押类型" style="width: 100%">
<el-option label="一线" value="一线" />
<el-option label="一类" value="一类" />
<el-option label="二类" value="二类" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="是否有经营佐证">
<el-switch v-model="form.bizProofActive" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="抵质押物三方所有">
<el-switch v-model="form.collThirdPartyActive" />
</el-form-item>
</el-col>
</el-row>
<!-- 中间业务标识 -->
<el-tab-pane label="中间业务标识" name="mid">
<el-row>
<el-col :span="12">
<el-form-item label="个人快捷支付">
<el-switch v-model="form.midPerQuickPayActive" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="个人电费代扣">
<el-switch v-model="form.midPerEleDdcActive" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="企业电费代扣">
<el-switch v-model="form.midEntEleDdcActive" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="企业水费代扣">
<el-switch v-model="form.midEntWaterDdcActive" />
</el-form-item>
</el-col>
</el-row>
</el-tab-pane>
<!-- 中间业务标识 -->
<el-divider content-position="left">中间业务标识</el-divider>
<el-row>
<el-col :span="12">
<el-form-item label="个人快捷支付">
<el-switch v-model="form.midPerQuickPayActive" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="个人电费代扣">
<el-switch v-model="form.midPerEleDdcActive" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="企业电费代扣">
<el-switch v-model="form.midEntEleDdcActive" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="企业水费代扣">
<el-switch v-model="form.midEntWaterDdcActive" />
</el-form-item>
</el-col>
</el-row>
<!-- 企业标识 -->
<el-tab-pane label="企业标识" name="ent">
<el-row>
<el-col :span="12">
<el-form-item label="净身企业">
<el-switch v-model="form.isCleanEntActive" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="开立基本结算账户">
<el-switch v-model="form.hasSettleAcctActive" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="制造业企业">
<el-switch v-model="form.isManufacturingActive" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="省农担担保贷款">
<el-switch v-model="form.isAgriGuarActive" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="纳税信用等级A级">
<el-switch v-model="form.isTaxAActive" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="县级及以上农业龙头企业">
<el-switch v-model="form.isAgriLeadingActive" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="普惠小微借款人">
<el-switch v-model="form.isInclusiveFinanceActive" />
</el-form-item>
</el-col>
</el-row>
</el-tab-pane>
</el-tabs>
<!-- 企业标识 -->
<el-divider content-position="left">企业标识</el-divider>
<el-row>
<el-col :span="12">
<el-form-item label="净身企业">
<el-switch v-model="form.isCleanEntActive" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="开立基本结算账户">
<el-switch v-model="form.hasSettleAcctActive" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="制造业企业">
<el-switch v-model="form.isManufacturingActive" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="省农担担保贷款">
<el-switch v-model="form.isAgriGuarActive" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="纳税信用等级A级">
<el-switch v-model="form.isTaxAActive" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="县级及以上农业龙头企业">
<el-switch v-model="form.isAgriLeadingActive" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="普惠小微借款人">
<el-switch v-model="form.isInclusiveFinanceActive" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
@@ -191,7 +185,6 @@ export default {
},
data() {
return {
activeTab: 'basic',
form: {},
rules: {
custIsn: [
@@ -317,3 +310,11 @@ export default {
}
}
</script>
<style scoped>
.workflow-create-form .el-divider {
margin: 8px 0 16px 0;
font-weight: 500;
font-size: 14px;
}
</style>