文档目录
动态表单功能

简介

本技术文档围绕 DouPHP 小程序“动态表单”能力,系统阐述表单引擎的核心实现与扩展方式。内容覆盖:

  • 表单配置解析(字段定义、排序、是否必填、选项)
  • 字段动态渲染(基于字段类型在前端/小程序侧渲染)
  • 数据验证规则(必填校验、防重复提交、XSS 清洗)
  • 模板引擎与数据绑定(前后端数据契约、默认值注入)
  • 用户体验优化(实时反馈、错误提示、提交后跳转/自动保存)
  • 开发示例(自定义字段类型、复杂验证逻辑、提交处理)
  • 常见问题(规则配置、数据格式转换、兼容性处理)

项目结构

动态表单由“核心服务 + 前台业务 + 后台管理 + 小程序前端”四部分组成:

  • 核心服务:提供跨端复用的基础能力(字段列表、名称映射、数据格式化等)
  • 前台业务:对外暴露表单列表、详情、提交接口;负责页面数据组装与提交流程控制
  • 后台管理:表单与字段的增删改查、数据查看与管理、状态切换
  • 小程序前端:展示表单列表与详情,收集用户输入并调用 API 提交
graph TB
subgraph "小程序前端"
MP_List["小程序-表单列表"]
MP_Detail["小程序-表单详情"]
end
subgraph "前台(网站)"
F_Controller["前台控制器"]
F_Service["前台服务"]
Core_Service["核心服务"]
end
subgraph "后台(管理)"
A_Controller["后台控制器"]
A_Service["后台服务"]
Model_Elem["字段模型"]
end
DB[("数据库: form / form_elements / form_data")]
MP_List --> F_Controller
MP_Detail --> F_Controller
F_Controller --> F_Service
F_Service --> Core_Service
A_Controller --> A_Service
A_Service --> Model_Elem
F_Service --> DB
Core_Service --> DB
A_Service --> DB

核心组件

  • 核心服务(FormService):提供表单列表、字段列表、字段名映射、序列化数据格式化等通用能力
  • 前台服务(FormService):构建列表页数据、详情页数据(含默认值)、提交处理(必填校验、防刷、XSS、落库)
  • 前台控制器(FormController):路由到视图或返回响应,统一异常与消息封装
  • 后台服务(FormService):表单与字段的 CRUD、数据分页与格式化、状态切换、删除
  • 后台控制器(FormController):管理端页面动作编排,审计日志记录
  • 字段模型(FormElements):字段表结构与可写字段定义

架构总览

动态表单采用“配置驱动 + 模板渲染 + 服务层校验”的架构:

  • 配置驱动:通过 form_elements 表定义字段类型、是否必填、选项、排序等
  • 模板渲染:前台根据字段类型渲染不同控件(文本、单选、下拉等),小程序侧按 post_data 初始化选择器索引
  • 服务层校验:前台服务在提交时执行必填校验、防重复提交、XSS 清洗,再持久化到 form_data
sequenceDiagram
participant MP as "小程序"
participant FC as "前台控制器"
participant FS as "前台服务"
participant CS as "核心服务"
participant DB as "数据库"
MP->>FC : GET /form/show?id=xx
FC->>FS : getShowPageData(id)
FS->>CS : getFormElementsList(form_id)
CS-->>FS : 字段列表
FS-->>FC : {form, post_data}
FC-->>MP : 表单详情(含默认值)
MP->>FC : POST /form/submit
FC->>FS : processSubmit(form_id, post, ip)
FS->>DB : 查询字段/必填项
FS->>FS : 必填校验/防刷/XSS
FS->>DB : 写入 form_data
FS-->>FC : {type,msg,url}
FC-->>MP : 成功/错误响应

详细组件分析

表单配置解析与字段元数据

  • 字段元数据来源:form_elements 表,包含 name、slug、type、unit、sort、must_fill、option、parent_id 等
  • 字段类型:input、select、textarea、radio(后台编辑面板限定)
  • 必填标记:must_fill=1 表示该字段为必填
  • 选项:option 以换行分隔存储,前端用于 select/radio 渲染
  • 排序:sort 决定字段显示顺序
flowchart TD
Start(["读取字段配置"]) --> Query["查询 form_elements<br/>按 sort,id 排序"]
Query --> BuildMeta["构建字段元数据<br/>name/slug/type/unit/must_fill/option"]
BuildMeta --> End(["返回字段列表"])

字段动态渲染与数据绑定

  • 前台详情页:根据字段类型生成对应控件,并为 select/radio 设置默认值(取 option 首项)
  • 小程序侧:加载详情时初始化 pickerIndexes,将 post_data 与字段 slug 绑定,提交时统一序列化
  • 数据绑定模式:post_data 作为双向绑定的载体,字段 slug 作为 key,确保提交键名与后端一致
sequenceDiagram
participant FE as "前端/小程序"
participant FS as "前台服务"
FE->>FS : 获取表单详情
FS-->>FE : {elements_list, post_data}
FE->>FE : 根据 type 渲染控件<br/>select/radio 初始化索引
FE->>FE : 用户交互更新 post_data
FE->>FS : 提交 post_data(JSON)

数据验证规则与提交处理

  • 必填校验:遍历 must_fill=1 的字段,缺失则返回 errors 映射
  • 防重复提交:同 IP 未读记录数≥1 时,提示“请勿重复提交”并返回重定向地址
  • XSS 清洗:提交前对数据进行清洗后再入库
  • 数据落库:将字段值按 slug 顺序组装为数组,序列化存入 data_box,并记录 ip、时间
flowchart TD
S(["开始提交"]) --> LoadFields["加载字段与必填项"]
LoadFields --> CheckEmpty{"必填项为空?"}
CheckEmpty -- 是 --> ReturnErr["返回 errors 映射"]
CheckEmpty -- 否 --> CheckRepeat{"同IP未读>=1?"}
CheckRepeat -- 是 --> ReturnMsg["返回 msg(防刷)"]
CheckRepeat -- 否 --> Clean["XSS 清洗"]
Clean --> Serialize["按字段顺序序列化"]
Serialize --> Insert["写入 form_data"]
Insert --> Redirect["返回成功与回跳地址"]

模板引擎与页面数据装配

  • 前台控制器将表单详情与 post_data 传入模板,模板根据字段类型渲染
  • 列表页支持分页,使用站点配置的分页大小
  • SEO 与面包屑信息一并注入,提升可访问性与搜索引擎友好度

后台管理与数据查看

  • 表单管理:创建、编辑、删除,支持图片上传与内容清洗
  • 字段管理:新增/编辑/删除字段,限制类型为 input/select/textarea/radio
  • 数据查看:分页查看提交数据,按关键字搜索,支持状态切换与删除
  • 审计日志:关键操作记录管理员行为

小程序端体验优化

  • 列表页:支持下拉加载更多,空数据时禁用继续加载
  • 详情页:初始化选择器索引,避免首次渲染空白;提交成功后支持自动跳转或显示成功态
  • 分享:设置分享标题,提升传播效果

依赖关系分析

  • 前台控制器依赖前台服务进行数据装配与提交处理
  • 前台服务依赖核心服务获取字段元数据与格式化数据
  • 后台服务依赖核心服务复用字段列表与数据格式化
  • 小程序前端依赖前台 API 获取表单详情与提交结果
graph LR
FC["前台控制器"] --> FS["前台服务"]
FS --> CS["核心服务"]
AC["后台控制器"] --> AS["后台服务"]
AS --> CS
MP["小程序前端"] --> FC

性能考虑

  • 分页与缓存:列表页使用分页减少数据传输;可结合缓存策略降低高频查询压力
  • 字段渲染:按 sort 顺序一次性加载字段元数据,避免多次请求
  • 提交优化:必填校验与防刷在前台服务完成,减少无效落库;XSS 清洗在入库前进行
  • 小程序体验:列表页懒加载与延迟加载提升滚动流畅度;选择器初始索引避免二次渲染

故障排查指南

  • 提交失败(必填缺失)
    • 现象:返回 errors 映射,提示某字段为空
    • 排查:检查 form_elements.must_fill 配置与前端 post_data 是否包含对应 slug
    • 参考路径:前台服务 FormService.php:112-153
  • 重复提交被拦截
    • 现象:提示“请勿重复提交”,并重定向到详情页
    • 排查:确认是否存在同 IP 未读记录;可在后台查看 form_data.status 与 if_read
    • 参考路径:前台服务 FormService.php:132-145
  • 字段不显示或顺序错乱
    • 现象:字段未渲染或顺序不符合预期
    • 排查:检查 form_elements.sort 与 type 配置;确认字段 slug 与前端 post_data 键一致
    • 参考路径:核心服务 FormService.php:43-66
  • 数据无法查看或格式异常
    • 现象:后台数据列表 data_box 显示异常
    • 排查:确认 formatDataBox 是否正确反序列化并按字段名映射
    • 参考路径:核心服务 FormService.php:79-97
  • 小程序选择器默认值不生效
    • 现象:select/radio 首次打开无默认值
    • 排查:确认 post_data 初始化与 pickerIndexes 同步更新
    • 参考路径:小程序表单详情 show.ts:15-49

结论

DouPHP 的动态表单以“配置驱动 + 模板渲染 + 服务层校验”为核心,实现了灵活的字段定义、稳定的数据校验与良好的前后端协作。通过核心服务抽象、前台服务编排与后台管理能力,开发者可以快速搭建各类采集场景,并在小程序中获得一致的体验。建议在生产环境结合缓存、限流与监控进一步提升稳定性与可观测性。

附录

  • 自定义字段类型
    • 在后台添加字段时,type 需为 input/select/textarea/radio;如需扩展新类型,需在模板与小程序侧增加渲染逻辑,并在前台服务中补充默认值与校验规则
    • 参考路径:后台服务 FormService.php:356-398
  • 复杂验证逻辑
    • 可在前台服务的 processSubmit 中扩展自定义校验(如正则、跨字段联动),并通过 errors 映射返回具体字段提示
    • 参考路径:前台服务 FormService.php:112-178
  • 表单提交处理
    • 小程序侧将 post_data 序列化为 JSON 提交;后台服务接收后进行必填校验、防刷、XSS 清洗与落库
    • 参考路径:小程序表单详情 show.ts:57-81
  • 数据格式转换
    • 后台查看数据时,通过 formatDataBox 将序列化数据转换为可读结构,便于审核与导出
    • 参考路径:核心服务 FormService.php:79-97
  • 兼容性处理
    • 字段排序与 slug 一致性是关键;确保前后端键名一致,避免提交错位
    • 参考路径:核心服务 FormService.php:43-66
添加日期:2026-10-05