普通视图

发现新文章,点击刷新页面。
昨天 — 2026年3月3日首页

如何用一份 JSON 配置搞定“法律计算器”的动态表单

2026年3月3日 15:18

引言:小明的工伤赔偿奇遇记

想象一下,当事人小明打开我们的“法律计算器”小程序,想算算工伤赔偿。

  • 场景 A:他手抖选了“劳动关系”,页面立刻弹出“月工资是多少?”;
  • 场景 B:他改主意选了“交通事故”,页面瞬间变身,开始问“伤残等级”;
  • 场景 C:他填了个“30000”的月薪,系统立马提示:“哥们,这超过社平工资 3 倍了,你确定没填错?”(后端异步校验)。

作为开发者,你是不是已经开始头疼了?如果针对劳动争议、交通事故、借贷纠纷等等法律业务都分别写一个 .vue 页面,光是维护 v-if/v-else 就得掉一半头发。万一明天产品经理说:“在这个表单中间加个‘案发地点’字段”,你是不是得发版重新提审?

拒绝写死代码! 今天我们来聊聊如何用 数据驱动UI 架构,打造一个“千人千面”的法律计算器。


一、 核心原理:把前端做成“乐高底板”

在传统的开发模式中,前端是“建筑师”,负责设计页面结构(Template);后端只是“搬砖工”,负责提供数据(Data)。

但在 数据驱动UI 架构下,角色反转了。前端退化成了一块纯粹的 “乐高底板”,而后端发来的 JSON 配置,就是那张 “搭建图纸”。前端不关心业务逻辑,只负责一件事:给什么积木,就搭什么房子。

1. 渲染引擎:v-for 的魔法

让我们看看核心渲染引擎 customForm/index.vue 是如何工作的。它的核心逻辑极其简单,就像是在遍历一份清单:

<!-- components/customForm/index.vue (精简版) -->
<template>
  <view class="custom-form">
    <!-- 第一层循环:遍历表单分组 (Section) -->
    <view v-for="(section, sIndex) in formConfig" :key="sIndex">
      <view class="section-title">{{ section.title }}</view>
      
      <!-- 第二层循环:遍历具体的题目 (Items) -->
      <view v-for="(item, iIndex) in section.items" :key="iIndex">
        
        <!-- 积木 A:普通输入框 (component === 3) -->
        <u-form-item v-if="item.component === 3" :label="item.title">
          <u-input v-model="formData[item.qId]" />
        </u-form-item>

        <!-- 积木 B:选择器 (component === 4) -->
        <u-form-item v-if="item.component === 4" :label="item.title">
          <view @click="openPicker(item)">{{ getLabel(item) }}</view>
        </u-form-item>

        <!-- 积木 C:复杂的利率选择器 (component === 9) -->
        <rate-selector 
          v-if="item.component === 9" 
          :init-value="formData[item.qId]"
        />
        
      </view>
    </view>
  </view>
</template>

前端不再写死 <input><select>,而是根据 JSON 中的 component 字段(3 代表输入框,4 代表选择器,9 代表复杂组件)动态决定渲染什么。

2. 每次修改表单都动态获取JSON数据

最精彩的部分来了。既然前端不写 v-if="salary > 30000",那条件分支怎么实现?

答案是:不要在前端做逻辑判断,把用户的每一次交互都告诉后端。

这是一个 (问后端) 的过程。在具体业务代码中,我们监听了表单的每一次变更:

// pages/enterpriseLaw/legalCalculator/form.vue

// 1. 用户修改了答案
handleFormChange(newAnswer) {
  // 更新本地答案池
  this.updateAnswers(newAnswer);
  
  // 2. 核心:带着当前的答案,去问后端“下一步该展示什么?”
  this.getDynamic(); 
},

async getDynamic() {
  // 3. 调用接口,把所有已填答案扔给后端
  const payload = { 
    appId: this.appId, 
    answers: this.answers 
  };
  
  // 4. 后端的大脑开始飞速运转,计算出新的题目列表
  const res = await this.$api.getDynamic(payload);
  
  // 5. 前端拿到新的 JSON,Vue 自动 diff 更新视图
  this.questions = res.data.questions;
}

点睛之笔:这就是“一份 JSON 配置”的真相。逻辑在后端,前端只是负责画图的“画笔”。 这样一来,无论是增加题目、修改逻辑分支,还是调整校验规则,都只需要后端改配置,前端代码一行都不用动!


二、 难点攻克:细节决定成败

痛点一:嵌套条件分支的“配置化”

如果题目之间有复杂的嵌套关系(例如 是否有借款 -> 有几笔 -> 第一笔利息 -> 怎么算的),JSON 结构该怎么设计?

我们采用 Section (分组) -> Group (实例) -> Items (题目) 的三层结构。Vue 的响应式系统在这里帮了大忙。当后端返回的 questions 数组发生变化(比如因为你选了“有借款”,数组里多了一个“借款详情”的 Section),Vue 会自动检测到数据的变化,并高效地修补 DOM。

// 后端返回的 JSON 结构示意
[
  {
    "groupTitle": "基本信息",
    "items": [ ... ]
  },
  {
    "groupTitle": "借款详情", // 只有当用户选了“有借款”才会返回这个 Section
    "isGroup": true,        // 标记为可重复的分组(如多笔借款)
    "items": [ ... ]
  }
]

痛点二:无缝嵌入异步校验

有些校验前端做不了,比如“赔偿金是否符合当地最新的法律标准”。这时候,我们需要把校验权也交给后端。

在代码中,我们设计了一个巧妙的 backendErrors 机制:

  1. 用户填完:触发 validateByBackend
  2. 后端校验:发现 Q101 题目的金额填错了,返回错误 Map:{ "q_101": "金额过大,请确认" }
  3. 前端标红
// customForm/index.vue

// 监听后端传来的错误对象
props: ['backendErrors'],

// 在模板中精准展示错误
<view v-if="backendErrors[item.qId]" class="backend-error">
  {{ backendErrors[item.qId] }}
</view>

这样,异步的业务校验就像本地校验一样自然流畅,用户根本感觉不到请求的延迟。

痛点三:原子组件的扩展(RateSelector)

这时候有人会问:“如果我要一个超级复杂的组件,比如‘LPR 利率计算器’,JSON 配置能描述清楚吗?”

当然可以!这就是 数据驱动UI 的灵活性。我们不需要用 JSON 描述组件内部的每一个 div,而是把这个复杂组件封装成一个原子积木

看看 components/customForm/RateSelector.vue,它内部包含了:

  • 日/月/年利率的切换
  • 百分比/千分比的换算
  • LPR 动态查询

但在表单引擎眼里,它只是一个普通的积木:

// 如果 component 代码是 9,我就渲染 RateSelector
<rate-selector v-if="rawItem.component === 9" ... />

这样,我们既保持了引擎的通用性(处理普通输入框),又保留了处理复杂业务的能力(通过自定义组件扩展)。


三、 总结:从“搬砖”到“搭积木”

数据流转图

最后,让我们用一张图来总结整个流程:

graph TD
    User[用户输入] -->|触发| Event[handleFormChange]
    Event -->|携带 Current Answers| API[调用 getDynamic 接口]
    API -->|发送至| Server[后端逻辑大脑]
    Server -->|计算条件分支/校验| Config[生成新的 JSON 配置]
    Config -->|返回| Frontend[前端 Vue 引擎]
    Frontend -->|Vue Reactivity| DOM[界面无感刷新]
    DOM -->|展示| User

架构优势

  1. 配置热更新: 运营人员想在表单里加一个“备注”字段?改一下数据库里的 JSON 配置就行了。用户端不需要发版,不需要更新,打开小程序就能看到新字段。这在法律法规频繁变动的行业简直是救命稻草。

  2. 逻辑复用: 我们只写了一套 customForm 引擎,却同时支持了“劳动争议”、“交通事故”、“民间借贷”等等法律业务的计算器。每个计算器只是后端数据库里的一条配置记录而已。

“偷懒”是程序员的第一生产力。 把复杂的逻辑甩给后端,把繁琐的渲染交给引擎,我们前端开发者,终于可以安心地喝一杯咖啡了。☕️


如果你对这套代码感兴趣,欢迎在评论区留言

❌
❌