导读:当业务部门第101次因为修改请假单的一个字段来找你排期时,是时候考虑将“表单定义”的权力交还给业务了。本文将深入探讨动态表单的核心理念、技术架构,并分享实用的开源方案。

一、 痛点引入:为什么我们不再硬编码表单?

在绝大多数企业内部管理系统中(OA、HRM、ERP),“请假申请”、“费用报销”、“离职流程”是最常见的三个需求。

传统开发模式下,每增加一种单据或修改一个字段,流程都是这样的:

  1. 产品经理提需求;

  2. Java/前端开发修改代码、前后端联调;

  3. 测试回归验证;

  4. 发布上线。

这种模式在面对多变的企业管理规则时,弊端非常明显:

  • 迭代周期长:一个简单字段的调整往往需要等待两周的发版窗口。

  • 研发资源瓶颈:程序员被大量的CRUD(增删改查)需求淹没,无法抽身去做更有深度的业务。

  • 沟通成本高:业务人员只能通过文字描述需求,无法所见即所得。

解决方案:将“表单的定义”与“表单的渲染”分离。我们需要一个动态表单(Dynamic Form)系统,让管理员在后台通过拖拽或配置的方式,直接生成业务模板,而无需重启服务或发布代码。

二、 核心架构:动态表单的三层模型

要实现“不写代码只配置”,我们需要在系统架构中引入“元数据(Metadata)”的概念。整个系统可以拆解为以下三层:

1. 数据定义层 —— 表单Schema(元数据)

这是系统的基石。我们不再用Java代码或HTML标签定义字段,而是使用一份结构化的JSON Schema来描述表单。

{
  "type": "object",
  "properties": {
    "leaveType": {
      "title": "请假类型",
      "type": "string",
      "enum": ["年假", "病假", "事假"],
      "ui:widget": "radio"
    },
    "startDate": {
      "title": "开始时间",
      "type": "string",
      "format": "date"
    },
    "reason": {
      "title": "请假事由",
      "type": "string",
      "maxLength": 200
    }
  }
}

优势:

  • 存储灵活:这份JSON存放在数据库的template_config表中,与业务代码解耦。

  • 版本控制:修改表单时会生成新版本的JSON,历史数据依然可以按照旧版JSON展示,完美支持数据归档。

2. 可视化设计层 —— 表单设计器(Form Builder)

这是提供给业务管理员的“画图工具”。在管理后台,管理员可以通过拖拽(Drag-and-Drop)将左侧的“文本框”、“下拉框”、“日期选择器”拖入画布。

关键交互:点击画布上的组件,右侧属性面板会动态变化,允许管理员修改字段的标题、是否必填、正则校验规则等。操作完成后,点击保存,系统将该画布状态序列化为上述的JSON Schema存入数据库。

3. 渲染与解析层 —— 表单渲染引擎(Form Renderer)

这是面向普通员工的展示层。当员工点击“发起申请”时,前端会向后端请求当前模板的JSON Schema,然后通过渲染引擎将JSON实时解析为可视化的HTML表单。

关键点:渲染引擎必须支持条件显示(例如选择“病假”时才显示“上传病例附件”控件),否则动态表单将毫无意义。

三、 开源方案图谱与选型指南

目前业界已经有不少成熟的解决方案,我们可以根据自身技术栈选择,不需要从零造轮子

针对纯前端渲染(React / Vue)

如果你的项目只需要解决“前端展示动态表单”的问题,可以引入以下库:

库名称

技术栈

特点与适用场景

Formily

React / Vue

阿里开源,功能极其强大,支持复杂联动校验,适合中后台复杂表单场景。

FormCreate

Vue 2/3

国内流行,基于JSON生成,文档丰富,上手快,适合中小型项目快速集成。

React JSON Schema Form

React

社区标准库,完全遵循JSON Schema规范,适合需要严格数据标准化的项目。

Form.io

框架无关

不仅提供前端渲染,还自带后端数据存储服务,适合全栈快速开发。

针对整体B端中后台低代码平台

如果你的需求不仅仅是表单,还包括列表页、详情页,甚至是整个后台页面的动态配置:

平台名称

技术栈

特点与适用场景

Amis | React

React

百度开源,通过JSON配置即可生成后台页面,内置了大量CRUD组件。

LowCodeEngine

React

阿里开源,面向构建者(Builder)的低代码设计器,适合二次开发定制。

针对审批流 + 表单一体化(请假/报销场景)

针对你提到的“请假、报销”需求,往往还需要配套的审批流引擎(BPMN)。以下两个开源项目实现了“表单”与“流程”的绑定:

  1. AntFlow-Designer:仿钉钉风格,后端Spring Boot,前端Vue3,集成了可视化流程设计器与表单设计器,适合国内企业管理风格。

  2. FlowLong(飞龙):纯Java开发的工作流引擎,支持灵活的CC(抄送)、跳转、驳回操作,对表单数据权限控制较好。

四、 避坑指南:动态表单的3个难点

虽然开源库解决了80%的问题,但在实施动态表单的过程中,以下几个深水区需要特别留意:

  1. 数据存储的“Schema漂移”

    • 问题:表单结构变了(如删除了“年龄”字段),但数据库里老数据的“年龄”值如何处理?

    • 策略:NoSQL优先。推荐使用MySQL的JSON类型字段存储表单提交值,或者是使用MongoDB。这样即使Schema变化,老数据依然保留完整字段,仅在渲染时通过Schema过滤掉已删除的字段。

  2. 权限与可见性的细粒度控制

    • 需求:部门经理能看到“成本中心”,普通员工看不到。

    • 实现:需要在Schema的ui:options中扩展permission属性,渲染时结合当前登录用户角色进行动态过滤,而不是仅依赖简单的hidden: true。

  3. 打印与导出的还原度

    • 痛点:动态生成的表单在屏幕上展示没问题,但打印成纸质版用于财务归档时,往往样式错乱。

    • 解决:不要依赖浏览器的window.print()。建议后端根据提交的JSON数据 + 模板ID,利用Apache POI(Word)或iText(PDF)在服务端动态生成固定版式文件,保证打印样式的稳定。

五、 总结

动态表单并不是一个高深莫测的技术,它的本质是**“数据驱动UI”。通过引入JSON Schema、可视化设计器和渲染引擎,我们可以将表单的新增或修改时间从“2周(研发排期)”缩短到“10分钟(管理员配置)”**。

对于正在规划企业内部系统的团队,我的建议是:先梳理业务场景

  • 如果仅需要表单,直接选型 Formily 或 FormCreate 作为核心渲染层。

  • 如果需要表单+流程(如复杂的审批流转),建议直接使用 AntFlow 或 FlowLong 这类提供完整解决方案的框架,不要强行将表单和流程硬编码拼接,避免日后维护灾难。

技术选型没有绝对的好坏,只有是否匹配团队的技术栈和业务复杂度。希望这篇文章能帮助你构建更灵活的企业级应用。