You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
11 KiB
11 KiB
| name | overview | status |
|---|---|---|
| 第三步-事前流程字段交互逻辑 | 详细说明非直接支付页面第三步中 pre_approval_flow 字段(事前流程选择)的交互逻辑、组件使用情况、数据流和预览展示。 | 已完成 |
第三步 - 事前流程字段交互逻辑
一、组件使用
1.1 组件引入
文件: czemc-budget-execution-frontend/src/views/payment/IndirectPayment.vue
import PreApprovalFlowPicker from '@/components/PreApprovalFlowPicker.vue'
1.2 组件渲染
位置: 第三步动态表单渲染部分(约第 296 行)
触发条件: 当字段的 element_type === 'oa_custom_model' 时
<!-- 事前流程实例 -->
<PreApprovalFlowPicker
v-else-if="field.element_type === 'oa_custom_model'"
v-model="formData[field.key]"
:model-id="field.model_id"
:placeholder="`请选择${field.label}`"
/>
1.3 组件属性说明
| 属性 | 类型 | 说明 | 来源 |
|---|---|---|---|
v-model |
Number|String|null |
双向绑定,存储选中的流程ID | formData[field.key] |
model-id |
Number|String |
流程模型ID,用于查询对应的流程实例 | field.model_id(从模板配置获取) |
placeholder |
String |
占位符文本 | 请选择${field.label} |
二、交互流程
2.1 交互流程图
flowchart TD
A[用户进入第三步] --> B{字段类型是否为 oa_custom_model?}
B -->|是| C[渲染 PreApprovalFlowPicker 组件]
B -->|否| D[渲染其他字段类型]
C --> E{是否已选择流程?}
E -->|否| F[显示"选择事前流程"按钮]
E -->|是| G[显示已选择的流程信息]
F --> H[用户点击按钮]
H --> I[打开选择对话框]
I --> J[加载流程实例列表]
J --> K[用户搜索/浏览流程]
K --> L[用户点击表格行选择]
L --> M[点击确定按钮]
M --> N[更新 v-model 值]
N --> O[关闭对话框]
O --> G
G --> P[显示流程编号和标题]
P --> Q[显示流程状态标签]
Q --> R[提供清除按钮]
R --> S{用户点击清除?}
S -->|是| T[清空选择]
T --> F
S -->|否| U[保持选择状态]
2.2 详细交互步骤
步骤1:初始状态
- 未选择时:显示"选择事前流程"按钮
- 已选择时:显示已选择的流程信息卡片,包含:
- 流程编号和标题
- 流程状态标签(带颜色)
- 清除按钮(右上角)
步骤2:打开选择对话框
- 点击"选择事前流程"按钮
- 打开宽度为 80% 的对话框
- 对话框标题:"选择事前流程实例"
步骤3:加载流程列表
API 调用: GET /api/budget/planned-expenditures/oa-flow-instances
请求参数:
{
custom_model_id: field.model_id, // 流程模型ID
page: 1, // 当前页码
page_size: 15, // 每页数量
keyword: '' // 搜索关键词(可选)
}
响应数据结构:
{
code: 0,
data: {
data: [ // 流程实例列表
{
id: 1,
no: 'FLOW-20250101-001',
title: '流程标题',
status: 'approved',
status_text: '已通过',
created_at: '2025-01-01 10:00:00',
related_count: 2, // 已关联数量
list_field_values: {}, // 列表字段值
list_fields: [] // 列表字段定义
}
],
total: 100, // 总记录数
list_columns: [ // 动态列定义(show_in_list=1的字段)
{
label: '字段标签',
name: 'field_name',
type: 'text'
}
]
}
}
步骤4:流程列表展示
表格列:
- 序号列 (#) - 宽度 60px
- 流程编号 (no) - 宽度 150px,支持溢出提示
- 流程标题 (title) - 最小宽度 250px,支持溢出提示
- 动态列 - 根据
list_columns动态生成,显示show_in_list=1的字段 - 流程状态 - 宽度 120px,显示状态标签
- 创建时间 - 宽度 180px
- 关联信息 - 宽度 200px,显示已关联数量
- 操作 - 宽度 120px,固定右侧,包含"查看详情"按钮
交互特性:
- 支持行点击选择(高亮当前行)
- 支持搜索功能(搜索流程编号、标题、列表字段)
- 支持分页(15/30/50/100 条每页)
- 支持查看详情(打开详情对话框)
步骤5:选择流程
- 用户点击表格行(高亮显示)
- 点击"确定"按钮
- 更新
v-model绑定的值(流程ID) - 关闭对话框
- 更新显示区域,展示已选择的流程信息
步骤6:清除选择
- 点击已选择流程卡片右上角的清除按钮(红色链接按钮)
- 清空
v-model绑定的值 - 恢复显示"选择事前流程"按钮
三、数据存储
3.1 表单数据存储
存储位置: formData[field.key]
存储格式:
- 未选择:
null或undefined - 已选择:流程ID(
Number或String)
示例:
formData = {
'element_123': 456, // 字段key: 流程ID
// ... 其他字段
}
3.2 后端存储
表: budget_planned_expenditure_element_values
字段映射:
planned_expenditure_id: 支出记录IDelement_id: 模板元素IDfield_key: 字段键名(如element_123)element_type:'oa_custom_model'value_text: 流程ID(字符串格式)flow_custom_model_id: 流程模型ID(冗余字段)flow_instance_id: 流程实例ID(冗余字段)flow_display_name: 流程显示名称(冗余字段)
存储逻辑: 通过 PlannedExpenditureController::persistElementValues() 方法保存
四、预览页面展示
4.1 流程详情加载
触发时机: 进入预览页面(第6步)时
函数: loadFlowDetailsForPreview()
逻辑:
- 遍历模板配置,收集所有
oa_custom_model类型的字段 - 提取这些字段的值(流程ID)
- 去重后调用批量查询接口
API 调用: GET /api/budget/planned-expenditures/oa-flow-details
请求参数:
{
flow_ids: [1, 2, 3, ...] // 流程ID数组
}
响应数据:
{
code: 0,
data: {
'1': { // key为流程ID
id: 1,
no: 'FLOW-001',
title: '流程标题',
display_name: 'FLOW-001 - 流程标题',
status: 'approved',
list_fields: [], // 列表字段
all_fields: [] // 全部字段(用于详情)
},
// ...
}
}
存储位置: flowDetailsMap.value(流程详情映射表)
4.2 预览格式化
函数: formatPreviewFieldValue()
处理逻辑:
if (elementType === 'oa_custom_model') {
if (!value) {
return '未选择流程'
}
const flowDetail = flowDetailsMap.value[value]
if (flowDetail) {
// 生成HTML,包含:
// 1. 流程基础信息(编号-标题)
// 2. 列表字段表格(如果有)
return html
}
return `流程ID: ${value}`
}
展示内容:
- 基础信息: 流程编号和标题(加粗显示)
- 列表字段表格: 显示所有
show_in_list=1的字段及其值
HTML 结构:
<div class="flow-preview">
<div class="flow-basic-info">
<strong>FLOW-001 - 流程标题</strong>
</div>
<table class="flow-list-fields">
<tr>
<td class="field-label">字段1:</td>
<td class="field-value">值1</td>
</tr>
<!-- ... 更多字段 ... -->
</table>
</div>
五、组件内部实现
5.1 核心状态
const selectedFlow = ref(null) // 当前选中的流程对象
const showSelectDialog = ref(false) // 选择对话框显示状态
const showDetailDialog = ref(false) // 详情对话框显示状态
const flowList = ref([]) // 流程列表数据
const listColumns = ref([]) // 动态列定义
const searchKeyword = ref('') // 搜索关键词
const loading = ref(false) // 加载状态
5.2 核心方法
loadFlowInstances()
- 加载流程实例列表
- 支持分页和搜索
- 处理动态列定义
handleSelectFlow(row)
- 处理表格行点击
- 设置
selectedRow
confirmSelect()
- 确认选择
- 更新
v-model - 关闭对话框
clearSelection()
- 清除选择
- 重置
v-model为null
viewFlowDetail(row)
- 查看流程详情
- 打开详情对话框
loadFlowDetail(flowId)
- 加载流程详情
- 使用缓存机制
- 优先从列表获取,其次从API加载
5.3 计算属性
const detailFields = computed(() => {
// 优先使用 all_fields,否则使用 list_fields
const flow = detailFlow.value
if (!flow) return []
if (Array.isArray(flow.all_fields) && flow.all_fields.length > 0) {
return flow.all_fields
}
if (Array.isArray(flow.list_fields) && flow.list_fields.length > 0) {
return flow.list_fields
}
return []
})
六、样式和UI
6.1 已选择状态展示
.selected-item {
display: flex;
align-items: center;
padding: 12px;
background: #f5f7fa;
border-radius: 4px;
border: 1px solid #e4e7ed;
}
.item-icon {
color: #409eff;
font-size: 20px;
margin-right: 12px;
}
.item-content {
flex: 1;
}
.item-title {
font-weight: 500;
color: #303133;
}
.item-meta {
margin-top: 4px;
}
.item-remove {
margin-left: 12px;
}
6.2 选择对话框
- 宽度:80%
- 支持搜索
- 表格支持行点击高亮
- 分页控件在底部
- 操作按钮在对话框底部
6.3 详情对话框
- 宽度:70%
- 使用
el-descriptions展示基础信息 - 使用
el-table展示列表字段 - 支持关联信息展示(如果有)
七、注意事项
7.1 数据一致性
- 流程ID必须与
model_id对应的流程模型匹配 - 选择流程后,流程详情会在预览页面加载
- 如果流程不存在,预览页面会显示"流程ID: xxx"
7.2 性能优化
- 流程列表支持分页,避免一次性加载过多数据
- 流程详情使用缓存机制,避免重复请求
- 预览页面批量加载所有流程详情,减少请求次数
7.3 错误处理
- API 请求失败时显示错误提示
- 流程不存在时显示友好的提示信息
- 网络错误时不影响其他功能
八、相关文件
8.1 组件文件
czemc-budget-execution-frontend/src/components/PreApprovalFlowPicker.vue
8.2 页面文件
czemc-budget-execution-frontend/src/views/payment/IndirectPayment.vue
8.3 API 文件
czemc-budget-execution-frontend/src/utils/api.jsplannedExpenditureAPI.getOaFlowInstances()- 获取流程实例列表plannedExpenditureAPI.getOaFlowDetails()- 批量获取流程详情
8.4 后端接口
GET /api/budget/planned-expenditures/oa-flow-instances- 获取流程实例列表GET /api/budget/planned-expenditures/oa-flow-details- 批量获取流程详情