可视化表单&试卷搭建平台技术详解

简介: 可视化表单&试卷搭建平台技术详解

hi, 大家好, 我是徐小夕. 年前和大家分享了新开发的轻量级零代码平台——橙子试卷, 主要用于可视化的搭建表单, 试卷等场景, 让不懂技术的人也能拖拽式创建自己的表单和试卷.

image.png

今天就来和大家分享一下橙子试卷的技术架构和技术实现, 如果你也在调研零代码, 低代码, 或者表单引擎等技术, 那么这篇文章也许可以给你带来一些灵感.

体验地址: https://turntip.cn/form-engine

技术栈

之前在开发 H5-dooring 零代码搭建平台时我采用的是React技术栈, 因为用 react 写复杂逻辑会更顺手, 好在 vue3 也支持了函数式的写法, 也提供了 hooks 机制, 让我们写逻辑驱动的应用更加方便, 所以橙子试卷 采用了国内最流行的 vue3 作为前端框架. 具体技术栈如下:

  • Vue3 前端框架
  • Vite 工程化工具
  • Typescript 类型加强
  • arco-design 精美的前端UI库
  • pinia 状态管理库
  • axios 请求库
  • json schema 数据存储规范
  • xijs 面向业务场景的js工具库
  • vue-echarts 数据分析图表库
  • koa2 服务端数据支持
  • koa-jwt 基于koa封装的jwt鉴权库

当然还有一些第三方组件这里就不一一介绍了. 我们的核心在于从零完整设计一套 MVP 的零代码搭建引擎, 所以后端部分, 大家可以替换成自己熟悉的 java, go, python 等语言.

技术架构

image.png

因为零代码表单引擎设计的核心是如何构造一套低成本且可扩展的组件库, 并快速应用到实际业务场景, 所以设计的核心就包括如下部分:

  • 可扩展的组件库系统
  • 灵活的拖拽搭建模式
  • 统一标准的DSL数据结构和数据规范
  • 一套可插拔的分析管理系统

接下来我会详细介绍这几块的技术实现, 当然实现思想和技术栈无关, 我们仍然可以把它应用到不同的技术体系中.

具体功能实现

1. 构造可扩展的组件库系统

image.png

因为我们的搭建场景是问卷, 试卷, 微页面, 所以组件库会围绕表单来扩展, 比如常用的:

  • 文本, 图片
  • 单选, 多选, 图片选择
  • 下拉框
  • 文本输入框
  • 文件上传
  • 电子签名
  • 评分

等等, 这些组件当然不能满足所有客户的业务场景, 所以我们要设计一种可扩展组件库, 并且开发成本较低的方案.

我们可以参考常见的低代码平台的设计思路:

image.png

简言之就是把核心UI和逻辑作为组件的主文件, 同时暴露标准的 的 可配置属性和可配置逻辑.

之所以强调“标准”, 是为了让不同组件能共用一套属性配置引擎, 从而让组件二开的成本大大降低(专注于组件的开发, 而不是配置的兼容).

image.png

其次为了尽可能让组件的配置更灵活, 我们需要提供一套标准的组件默认属性, 让用户可以根据默认属性来配置自己的个性化的样式, 那么我们的组件就需要这么来设计:

image.png

这里以橙子试卷文本组件给大家举个例子.

文本组件的主文件:

<template>
  <div
    :class="{
      text: true,
      justify: editorStore.data[index].align == 'justify',
      [editorStore.data[index].animation]: true,
    }"
    :style="{
      paddingTop: editorStore.data[index].padding[0] + 'px',
      paddingRight: editorStore.data[index].padding[1] + 'px',
      paddingBottom: editorStore.data[index].padding[2] + 'px',
      paddingLeft: editorStore.data[index].padding[3] + 'px',
      color: editorStore.data[index].titleColor,
      fontSize: editorStore.data[index].titleSize + 'px',
      fontWeight: editorStore.data[index].titleWeight,
      textAlign: editorStore.data[index].align,
      animationDelay: editorStore.data[index].delay,
      animationIterationCount: editorStore.data[index].number,
      cursor: 'pointer',
    }"
    @click="jump(editorStore.data[index].link)"
  >
    {{ editorStore.data[index].titleText }}
  </div>
</template>
<script setup lang="ts">
import { useEditorStore } from "@/store";
const editorStore = useEditorStore();
const jump = (link: string) => {
  window.location.href = link;
};
defineProps(["index"]);
</script>

文本组件的可配置属性:

export default class Text {
    component: TextPropType;
    constructor(id: string) {
        this.component = {
            component: 'text',
            type:'editor.text',
            id,
            check: true,
            titleText: 'https://turntip.cn/form-engine',
            titleColor: 'black',
            titleSize:16,
            titleWeight:'500',
            padding: [0, 0, 0, 0],
            margin: [10, 10, 10, 10],
            animation:'',
            direction: 'center',
            link:'https://turntip.cn/formManager',
            delay:2,
            attrbite: [
                {
                    name: 'editor.titleText',
                    field: 'titleText',
                    component: 'textarea'
                },
                {
                    name: 'editor.padding',
                    field: 'padding',
                    component: "padding",
                    props: {
                        min: 0,
                        type:'padding'
                    }
                },
                {
                    name: 'editor.margin',
                    field: 'margin',
                    component: "padding",
                    props: {
                        min: 0,
                        type:'margin'
                    }
                },
            ]
        }
    }
}

通过这种方式, 我们只需要根据业务需求实现自己的组件, 编写组件可配置的属性json, 即可通过配置引擎来动态生成组件的可编辑面板, 从而让非技术人员轻松编辑组件.

通过以上的方式, 我们可以轻松开发各种自定义的组件, 提供给用户使用:

image.png

2. 灵活的拖拽搭建模式

image.png

对于表单场景, 我们不需要特别复杂的布局交互, 所以这里我才用拖拽排序来实现页面的搭建, 同时支持组件快捷复制和删除.

目前 vue3 的比较成熟的拖拽组件有:

  • vuedraggable
  • vue3-draggable-resizable

这里选择vuedraggable 来实现拖拽排序, 并对其进行上层封装, 实现体验更好的组件搭建排序效果.

当然还有很多优秀的拖拽库, 如果大家对vue3-draggable-resizable 感兴趣, 也可以试试, 它支持网格布局和自由布局, 可以实现更自由的布局搭建效果:

image.png

3. 统一标准的DSL数据结构和数据规范

在组件库设计中我们为了统一管理和维护组件和组件的属性配置, 需要定义统一化的 DSL 结构, 这个结构包含了组件的如下信息:

  • 组件元数据
  • 位置信息
  • 样式信息
  • 事件 / 交互
  • 埋点定义(高级配置)

后4个都好理解, 这里介绍一下组件元数据, 它的价值在于定义组件的基本信息:

  • 组件类型
  • 组件名称
  • 图标
  • 初始化数据
  • 组件路径 (高级, 可选)
  • 状态 / 版本 (高级, 可选)

通过对 元信息 的定义, 我们可以很方便的建立更系统的组件库, 比如支持组件分类, 组件版本切换, 组件加载(通过路径元信息来加载远程组件).

所以我们需要尽可能规范统一的定义组件的通用规则和自定义规范, 以便让不同组件都遵行统一的规则来实现零代码搭建引擎的设计.

这里还是以橙子试卷为例子, 来介绍一下我们统一的DSL:

image.png

首先我们看看文本的元信息:

{
    name: 'editor.text', // 组件名称
    component: IconLanguage, // 组件图标
    type: 'text' // 组件类型
}

这是一个简单的元信息, 它可以帮我们快速识别组件, 并为画布提供组件更具体的渲染信息, 不同组件都通过统一的配置来定义, 可以让我们的渲染器更加高效的渲染组件, 并降低组件维护成本.

在介绍组件的内容中我已经介绍了组件接受的 json 配置结构, 这里分享一个由多个组件组成的完整页面的 DSL 结构和实际代码:

image.png

案例代码:

{
    "id": "5137706621235472",
    "title": "2024前端笔试题",
    "author": "徐小夕",
    "desc": "页面描述",
    "icon": "",
    "bgColor": "",
    "bgImage": "",
    "isLogin": false,
    "data": [
        {
            "component": "sign",
            "type": "editor.sign",
            "id": "JelhSP",
            "check": false,
            "titleText": "请在此处签名",
            "titleColor": "black",
            "margin": [
                10,
                10,
                10,
                10
            ],
            "limit": 1,
            "btnColor": "#165DFF",
            "titleSize": 15,
            "titleWeight": "500",
            "analysis": ""
        },
        {
            "component": "math",
            "type": "editor.math",
            "id": "3-U9XA",
            "check": true,
            "titleText": "数学题目:5^9>\\pi",
            "titleColor": "#D41C1C",
            "options": [
                {
                    "label": "A",
                    "value": "苹果"
                },
                {
                    "label": "B",
                    "value": "香蕉"
                }
            ],
            "symbol": "A,B,C...",
            "direction": "horizontal",
            "optionsColor": "black",
            "analysis": "",
            "auto": "",
            "margin": [
                10,
                10,
                10,
                10
            ],
            "scores": 0,
            "required": false
        },
    ]
}

有了以上的统一 DSL 结构, 我们就可以轻松通过 JSON 来渲染页面, 同时也有更多的想象空间, 比如:

  • 通过DSL来实现跨端渲染搭建
  • 通过DSL来实现多人协作共享
  • 通过DSL来实现A出码能力
  • 通过AI学习DSL来批量自动化生产页面

4. 可插拔的分析管理系统

一个可视化零代码解决方案一定包含完整的用户使用链路, 即从搭建到投放再到信息收集的完整分析链路.

image.png

当然不同的公司业务分析需求不同, 所以需要支持纯粹的数据收集和流转, 以便供不同业务使用.

目前橙子试卷提供了一套完整的数据收集能力, 对于试卷场景, 也提供了自动打分机制, 可以一键分析数据情况:

image.png

当然这都是可以基于自身规则自己二次开发的, 橙子试卷 只是提供了一套案例参考.

应用场景和价值

  • 帮助中小企业或者个体提供一套低成本零代码表单搭建解决方案,且不止于表单/试卷
  • 基于橙子试卷的最佳实践, 轻松扩展出更多的搭建业务场景
  • 开箱即用的组件和模版管理最佳实践, 积累和沉淀内部技术资产
  • 结合AIGC, 创造更强大的生产力工具

体验地址: https://turntip.cn/form-engine

技术交流:


目录
相关文章
npm 切换镜像后,npm i 安装依然卡,需要好久才完成
npm 切换镜像后,npm i 安装依然卡,需要好久才完成
1442 0
|
7月前
|
Java 测试技术 Linux
Apache JMeter 2.9 简单上手教程(附下载包)
JMeter是一款开源性能测试工具,用于模拟多用户并发访问网站或接口,检测服务器负载能力。本文介绍其基本使用:下载解压、配置JDK、启动运行,通过创建线程组、添加HTTP请求和监听器,完成对百度首页的并发测试,并查看响应时间与错误率,帮助初学者快速上手性能测试。
|
关系型数据库 MySQL 数据安全/隐私保护
windows mysql8 安装后 提示密码不对,修改下密码认证方式就可以了
windows mysql8 安装后 提示密码不对,修改下密码认证方式就可以了
3209 3
|
消息中间件 存储 Cloud Native
基于 RocketMQ 的云原生 MQTT 消息引擎设计
本文将介绍阿里云如何将 Serverless 架构应用于消息队列,有效降低运营成本,同时利用云原生环境的特性,为 IoT 设备提供快速响应和灵活伸缩的通讯能力。
688 127
|
SQL 关系型数据库 MySQL
京东面试:MySQL MVCC是如何实现的?如何通过MVCC实现读已提交、可重复读隔离级别的?
1.请解释什么是MVCC,它在数据库中的作用是什么? 2.在MySQL中,MVCC是如何实现的?请简述其工作原理。 3.MVCC是如何解决读-写和写-写冲突的? 4.在并发环境中,当多个事务同时读取同一行数据时,MVCC是如何保证每个事务看到的数据版本是一致的? 5.MVCC如何帮助提高数据库的并发性能?
京东面试:MySQL MVCC是如何实现的?如何通过MVCC实现读已提交、可重复读隔离级别的?
|
存储 人工智能 自然语言处理
2025年适用大中企业的CRM系统综合对比
在数字化转型浪潮中,CRM系统对大中型企业至关重要。本文对比了2025年适用于大中型企业的4款CRM系统:纷享销客、Salesforce、销售易和红圈CRM。从功能特点、集成拓展性、实施服务、客户评价四个维度展开分析,展现各系统优势与局限,为企业在选择CRM系统时,综合自身业务需求、预算和发展规划等因素做出决策提供参考。
|
数据采集 机器人 测试技术
SeleniumBase在无头模式下绕过验证码的完整指南
本文详细介绍了如何在SeleniumBase的无头模式下绕过验证码,通过使用代理IP(以爬虫代理为例)、设置User-Agent和Cookie等手段提升爬虫效率。文章首先分析了无头模式下面临的验证码挑战,然后提供了具体的策略和代码示例,包括浏览器设置、代理IP配置及模拟用户行为的方法。最后,通过一个访问大众点评网站并绕过验证码的完整代码示例,展示了如何在实际场景中应用这些技术,应对现代网站的反爬虫机制。此外,还提供了一些提高爬虫效率的实用技巧,如代理池轮换、设置合适延迟和分布式爬虫等。
1863 1
|
缓存 安全 Java
面试中的难题:线程异步执行后如何共享数据?
本文通过一个面试故事,详细讲解了Java中线程内部开启异步操作后如何安全地共享数据。介绍了异步操作的基本概念及常见实现方式(如CompletableFuture、ExecutorService),并重点探讨了volatile关键字、CountDownLatch和CompletableFuture等工具在线程间数据共享中的应用,帮助读者理解线程安全和内存可见性问题。通过这些方法,可以有效解决多线程环境下的数据共享挑战,提升编程效率和代码健壮性。
484 6
|
监控 前端开发 JavaScript
浏览器节能机制导致Websocket断连的坑
浏览器节能机制导致Websocket断连的坑
489 1
|
存储 数据可视化 Python
使用python moviepy提取视频中的音频,同时对音频数据进行数据可视化分析
使用python moviepy提取视频中的音频,同时对音频数据进行数据可视化分析
1033 0