Skip to content

审批接入(业务表单)

业务表单是指使用独立的业务数据表存储数据,同时接入工作流引擎实现审批的方式。适合有复杂业务逻辑、需要数据关联查询、自定义 UI 的场景。

1. 操作步骤

1.0 第零步:开发业务表单

在创建流程之前,需要先完成业务表单的前后端开发。具体开发规范参见下文 第 3 节:业务表单开发规范

1.1 第一步:定义流程

① 新建流程模型

与流程表单相同,进入「流程中心 → 流程模型」,点击「新建模型」按钮:

新建流程模型

填写基本信息:

  • 流程标识:唯一标识,如 oa_seal_apply_billhrm_employee_entry_bill
  • 流程名称:显示名称,如「用印申请单」「员工入职单」
  • 流程分类:选择流程所属分类(OA、人力等)
  • 流程图标:选择图标
  • 流程描述:可选描述

② 设计表单

在「表单设计」步骤,选择「业务表单」类型(区别于流程表单),然后配置以下路由信息: 流程表单关联

  • 表单提交路由:指向业务表单的创建/编辑页面路由,如 /oa/seal/sealapply/info
  • 表单查看路由:指向业务表单的详情查看页面路由,通常与提交路由相同

这两个路由告诉流程引擎:发起流程时跳转到哪个页面填写表单,审批时跳转到哪个页面查看详情。

③ 设计流程

与流程表单完全相同,选择流程设计器(BPMN 或 钉钉/飞书设计器),设计审批流程节点。

流程设计

每个审批节点可配置:

  • 审批人规则:指定角色、部门、岗位等
  • 表单字段权限:每个字段可设为只读、可编辑、隐藏(详见 业务表单字段权限
  • 多人审批方式:会签、或签、依次审批
  • 操作按钮:通过、拒绝、驳回、转办、委派等

④ 发布流程

流程设计完成后,点击「发布」按钮,流程即可使用。

发布流程

1.2 第二步:发起流程

用户在业务列表页点击「新建」,填写业务表单后提交。后端同时创建业务记录并启动流程实例。

发起流程

1.3 第三步:审批流程

审批人在「待办任务」中点击审批时,系统跳转到业务表单的详情页,展示业务数据和审批操作按钮。

待办任务

支持的审批操作:

  • 通过:同意当前审批
  • 不通过:拒绝流程
  • 驳回:退回到指定节点
  • 转办:转交给其他人审批
  • 委派:委派给其他人审批后再返回
  • 加签:临时增加审批人

2. 业务表单 vs 流程表单

维度流程表单业务表单
数据存储Flowable 变量表(ACT_RU_VARIABLE独立业务表
表单设计在线拖拽设计器(form-create)手写 Vue 组件(BasicForm)
开发成本零代码需要前后端开发
灵活性受限于设计器能力完全自定义
数据查询需要通过 Flowable API 或特殊 SQL标准 SQL
业务逻辑简单可处理复杂业务
子表/明细不支持支持一对多明细表
附件管理基础上传AttachmentService 统一管理
字段权限设计器原生支持通过动态字段权限扩展支持

3. 业务表单开发规范

业务表单的开发需要前后端配合完成。以下是完整的产物清单和关键规范,也可以将本节内容作为 AI 代码生成的提示词使用。

完整的代码生成规范文档:ruoyi-office-prompt/流程表单-代码生成规范.md

3.1 完整产物清单

每个业务表单需要产出以下文件:

层级文件说明
SQL{表名}.sql表结构(主表 + 子表)
SQL{表名}_menu.sql菜单与权限
SQL{字典名}_dict.sql新字典类型(如有)
枚举XxxBillTypeEnum在模块 BillTypeEnum 中新增枚举值
枚举ErrorCodeConstants新增错误码
后端XxxBillDO.java数据对象
后端XxxBillSaveReqVO.java保存请求 VO
后端XxxBillRespVO.java响应 VO
后端XxxBillPageReqVO.java分页请求 VO
后端XxxBillMapper.javaMapper 接口
后端XxxBillService.javaService 接口
后端XxxBillServiceImpl.javaService 实现(含 FlowBillService)
后端XxxBillController.javaController
前端api/{模块}/{业务}/index.tsAPI 定义
前端views/.../list/index.vue列表页
前端views/.../list/data.ts列表配置
前端views/.../info/index.vue表单页(含审批操作)
前端views/.../info/data.ts表单配置

3.2 数据建模(表结构)

所有流程表单类单据主表应包含以下通用字段:

sql
CREATE TABLE xxx_bill (
  id                  BIGINT       NOT NULL AUTO_INCREMENT COMMENT 'ID',
  bill_code           VARCHAR(50)  NOT NULL COMMENT '单据编号',
  process_instance_id VARCHAR(64)  DEFAULT NULL COMMENT '流程实例编号',
  process_status      TINYINT      DEFAULT 0 COMMENT '单据状态(0草稿 1审批中 2审批通过 3审批拒绝 4已取消)',

  creator_name        VARCHAR(100) DEFAULT NULL COMMENT '创建者姓名',
  company_id          BIGINT       DEFAULT NULL COMMENT '公司ID',
  company_name        VARCHAR(200) DEFAULT NULL COMMENT '公司名称',
  dept_id             BIGINT       DEFAULT NULL COMMENT '部门ID',
  dept_name           VARCHAR(200) DEFAULT NULL COMMENT '部门名称',
  remark              VARCHAR(500) DEFAULT NULL COMMENT '备注',

  -- 其他业务字段 ...

  tenant_id           BIGINT       NOT NULL DEFAULT 0 COMMENT '租户编号',
  creator             VARCHAR(64)  DEFAULT '' COMMENT '创建者',
  create_time         DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  updater             VARCHAR(64)  DEFAULT '' COMMENT '更新者',
  update_time         DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  deleted             BIT(1)       NOT NULL DEFAULT b'0' COMMENT '是否删除',
  PRIMARY KEY (id)
);

关键约定:

  • 表名{模块前缀}_{业务名}_bill,如 oa_car_apply_billhrm_employee_entry_bill
  • 单据编号bill_code 字段,使用 BillCodeUtils 自动生成
  • 流程关联process_instance_id 关联 Flowable 流程实例,process_status 跟踪审批状态
  • 组织维度:统一 company_id / company_name + dept_id / dept_name

3.3 后端关键实现

审批流程集成

Service 实现类必须实现 FlowBillService 接口:

java
public class XxxBillServiceImpl implements XxxBillService, FlowBillService<OaBillTypeEnum> {

    @Override
    public OaBillTypeEnum getSupportedBillType() {
        return OaBillTypeEnum.XXX;
    }

    @Override
    public void updateProcessStatus(Long billId, Integer processStatus) {
        xxxBillMapper.updateById(new XxxBillDO().setId(billId)
            .setProcessStatus(processStatus));
    }
}

发起流程

java
// 设置流程状态为审批中
billDO.setProcessStatus(BpmTaskStatusEnum.RUNNING.getStatus());

// 构建流程变量
Map<String, Object> variables = BpmProcessVariableUtils.buildBillVariables(saveReqVO);

// 提交流程实例
processInstanceApi.submitProcessInstance(...);

单据编号

java
if (StringUtils.isBlank(saveReqVO.getBillCode())) {
    saveReqVO.setBillCode(BillCodeUtils.generateBillCode(
        SystemEnum.OA, OaBillTypeEnum.XXX));
}

附件处理

java
// 必须使用 AttachmentService,不要用字符串字段存储
if (saveReqVO.getAttachments() != null) {
    attachmentService.saveAttachmentList(
        OaBillTypeEnum.XXX.getTypeCode(),
        billDO.getId(),
        saveReqVO.getAttachments());
}

3.4 前端关键实现

页面结构

必须采用 list/ + info/ 分离结构,不使用 modal 弹窗:

views/{模块}/{功能}/
├── list/
│   ├── index.vue      # 列表页(useVbenVxeGrid)
│   └── data.ts        # 搜索表单 + 表格列配置
└── info/
    ├── index.vue      # 表单页(BasicForm + 审批操作)
    └── data.ts        # 表单 schema 配置

表单页核心结构

vue
<template>
  <Loading :spinning="loading">
    <BasicForm
      v-if="initialized"
      :field-permission="effectiveFieldPermission"
      :is-approval="props.isApproval"
      :process-status="formData.processStatus"
      :form-schema="formSchema"
      ref="basicFormRef"
    >
      <template #form-extension>
        <!-- 业务扩展区块 -->
        <!-- 明细表格(useVbenVxeGrid) -->
        <!-- 附件区块(AttachmentList) -->
      </template>
    </BasicForm>
  </Loading>
</template>

字段权限集成(新表单必须使用)

新开发的业务表单必须接入动态字段权限,在流程设计器中按节点配置字段的只读/可编辑/隐藏:

typescript
import type { BusinessFieldPermission } from '#/views/bpm/composables';
import { getProcessDefinition } from '#/api/bpm/definition';
import { getApprovalDetail } from '#/api/bpm/processInstance';

const PROCESS_DEFINITION_KEY = 'oa_xxx_bill';
const initialized = ref(false);
const localFieldPermission = ref<BusinessFieldPermission>();
const effectiveFieldPermission = computed(
  () => props.businessFieldsPermission || localFieldPermission.value,
);

async function loadFieldPermission() {
  if (props.viewType || props.processInstance) return;
  const def = await getProcessDefinition(undefined, PROCESS_DEFINITION_KEY);
  if (!def?.id) return;
  const detail = await getApprovalDetail({
    processDefinitionId: def.id,
    activityId: 'StartUserNode',
  });
  if (detail?.businessFieldsPermission) {
    localFieldPermission.value = detail.businessFieldsPermission;
  }
}

onMounted(async () => {
  initFormSchema();
  loading.value = true;
  try {
    await Promise.all([loadData(), loadFieldPermission()]);
  } finally {
    loading.value = false;
    initialized.value = true;
  }
});

审批前保存(beforeApproval)

当审批节点需要审批人回填数据时,需实现 beforeApproval

typescript
async function beforeApproval(): Promise<boolean> {
  if (!props.isApproval) return true;
  const permConfig = basicFormRef.value?.hasPermissionConfig;
  const editable = basicFormRef.value?.editableFields;
  if (permConfig && editable?.length > 0 && basicFormRef.value) {
    const { valid } = await basicFormRef.value.validateForm();
    if (!valid) {
      message.error('表单校验不通过,请先完善表单信息');
      return false;
    }
    const formValues = await basicFormRef.value.getFormValues();
    await saveXxxBill({ ...formData.value, ...formValues });
    return true;
  }
  return true;
}

defineExpose({ beforeApproval, loadData, handleSaveAndSubmit });

3.5 AI 代码生成

上述开发规范可以直接作为 AI 代码生成的提示词使用。推荐的提示词模板:

请参照 @参照模块 的完整实现,生成 [功能名称] 功能代码。

【强制要求】
1. 后端:严格参照参照 Service 的附件处理、审批流程、单据编号生成方式
2. 前端:严格参照参照前端的 list/info 分离结构、组件使用方式
3. 必须完整阅读参照代码后再生成,确保结构、命名、实现方式完全一致

【关键检查点】
- 附件:使用 AttachmentService(后端)/ AttachmentList(前端)
- 页面:list/info 分离,不使用 modal
- 明细:使用 useVbenVxeGrid,禁止 Ant Design Table
- 字段权限:接入 loadFieldPermission + initialized + v-if

【禁止事项】
- 不要自行简化或创新实现方式
- 不要使用字符串存储附件
- 不要使用 modal 弹窗表单

完整规范文档:ruoyi-office-prompt/流程表单-代码生成规范.md,包含表结构规范、菜单权限 SQL、后端规范、前端组件规范、明细表格规范、检查清单等全部内容。

4. 业务表单集成原理

业务表单与流程引擎的集成通过以下机制实现:

  1. 发起流程:业务 Service 调用 BpmProcessInstanceApisubmitProcessInstance(),传入 processDefinitionKey 和业务变量
  2. 流程变量:单据编号、公司、部门等关键信息作为流程变量存储,供流程条件分支使用
  3. 状态同步:通过 FlowBillService 接口,流程状态变化时自动回调业务 Service 更新 processStatus
  4. 页面跳转:流程模型中配置的表单路由,控制发起和审批详情页的跳转目标
发起申请 → 创建业务记录 → 启动流程实例 → 审批人处理
    ↑                                          ↓
    └──── 状态同步 ←── FlowBillService ←── 审批结果

5. RuoYi Office 扩展:字段权限动态配置

RuoYi Office 在业务表单的基础上,扩展了字段权限动态配置功能。在流程设计器中按审批节点配置业务表单字段的只读、编辑、隐藏权限,无需硬编码。

详见 《业务表单字段权限》