☰
信息管理小程序开发平台:配置驱动CRUD快速开发实战
2026/10/15 4:31:12 网站建设 项目流程

信息管理类小程序大概是所有小程序需求里最“看起来简单、做起来啰嗦”的一类。客户名单、商品目录、库存台账、拜访记录、预约排班……业务名词换了一茬又一茬,底层要的东西翻来覆去就是那么几样:一个能分页搜索的列表、一个能增改删的表单、一个能看详情的页面。我见过太多人为了这几个页面加班到深夜,也下载过不少标着“含源码”的Demo,解压之后发现业务是写死的,换个字段就要动七八个文件。这篇要聊的“信息管理小程序开发平台(含源码)”,走的恰恰是另一条路:把增删改查沉淀成通用能力,新增一个信息模块只需要配置数据模型,页面和后端接口都会自动出现。换句话说,它给你的不是一只已经炖好的鸡,而是一套能持续出菜的厨房。接下来我从平台设计、源码结构、跑通步骤、核心代码和实测踩坑这几个角度,把这份源码真正讲透。

1. 重复造轮子的信息管理小程序,缺的不是代码而是建模能力

1.1 信息管理类小程序的“万变不离其宗”

只要做过几个小程序项目,你一定会发现一个规律:所谓信息管理,拆开看就是“一堆字段 + 一个列表 + 一个表单 + 一个详情”。客户管理是客户名称、联系人、电话、跟进状态;商品管理是商品名称、分类、价格、库存;预约管理是客户、项目、时间、备注。字段不一样,交互模型几乎一模一样。

我把常见场景拉了一张表,你对照看看是不是这个道理:

业务场景常见模块划分共同点
客户关系管理客户档案、联系记录、跟进计划列表 + 搜索 + 详情 + 编辑
进销存商品目录、供应商、入库单、出库单主从表、单据状态
预约服务项目、排班、预约单时间字段 + 状态流转
物业巡检楼栋、设备、巡检任务现场拍照、记录上报

这些模块单独看都不难,难的是每个都要从零写一遍列表页的加载态、空态、搜索防抖、分页参数、表单校验、删除确认。更难受的是,下个需求只是把“客户名称”换成“设备名称”,你就得复制一个页面,改字段名,再处理一遍几乎一样的逻辑。这种重复劳动不是技术问题,而是建模问题——你一直在用“写代码”的方式表达“数据结构”,却没有把数据结构本身当成可以配置的东西。

1.2 为什么说“开发平台”比“业务Demo”更有价值

市面上带“含源码”的项目很多,但大部分是业务Demo:登录怎么做、订单怎么提交、商品怎么展示,全是写死的。你拿来学习可以,拿来复用就痛苦,因为改一个字段牵扯到的文件太多,改着改着发现和重写差不多。

这份“信息管理小程序开发平台”的价值,在于它把信息管理场景里最通用的部分做成了骨架:数据模型配置、通用列表页、通用表单页、通用详情页、通用CRUD接口。你要做的新模块,只要在配置里告诉它“有哪些字段、字段叫什么、哪些要展示、哪些要搜索”,页面和接口就自动有了。

我理解它的目标用户有三类:一是需要快速交付多个信息管理小程序的人,靠配置就能攒出模块;二是想把团队开发流程标准化的人,新成员不需要理解全部业务也能维护简单模块;三是正在学前后端分离开发的学生或转行者,这套代码比一堆业务Demo更能帮你理解“元数据驱动”到底是怎么回事。

1.3 这个平台的边界:能做什么、不能做什么

拿到源码先别急着扩展,先给平台框个边界。它擅长的是结构化数据的管理:单表为主、字段相对固定、交互以增删改查为核心。它不擅长的也很明显:复杂审批流、多级联动、实时协同编辑、复杂报表分析。如果你要做一个“进销存”这种带主从表和库存扣减逻辑的系统,通用配置层能帮你解决录入界面,但库存计算和单据状态流转仍要单独写业务逻辑。

我的建议是:能用配置解决的模块优先用配置,配置撑不住的模块再通过扩展接口或自定义页面补齐。平台的意义不是代替你思考业务,而是把你从“写腻了的增删改查”里解放出来,让你把时间花在真正有业务价值的地方。

2. 平台的样子:前后端分离 + 数据模型配置驱动的整体架构

2.1 技术选型:小程序端原生,服务端 Node.js + Express,数据库 MySQL

拿到源码第一件事,先弄明白它为什么选这套技术栈。我根据源码常见的实现方式,把这套平台的选型逻辑拆开看:

端技术选型理由
小程序端原生 WXML / WXSS / JavaScript无额外依赖、真机兼容性最好、上手门槛低
服务端Node.js 16 + Express 4前后端语言统一,生态成熟,部署简单
数据库MySQL 5.7 / 8.0结构化数据强约束,事务可靠,资料最多

可能有人会问,为什么不用 uni-app 跨端,为什么不用 Java Spring Boot。我的看法是:uni-app 确实能一套代码跑多端,但调试链路更长,插件兼容性问题更多,对“信息管理”这种重表单、重交互的场景,原生小程序反而更稳;Spring Boot 在企业级没问题,但对个人开发者和小团队来说太重了,一个 CRUD 平台用 Express 这种轻量框架,启动快、内存占用低、心智负担小,改起来也快。

技术选型没有绝对正确,关键是匹配场景。这套平台面向的是中小企业信息化、个人工具类小程序、内部管理系统,Node.js + MySQL 的组合足够覆盖,而且前端开发者不用切换语言,服务端代码看起来也不费劲。

2.2 数据模型配置是如何“长出”业务功能的

平台的核心不是路由,不是页面,而是“数据模型配置”。这个概念也叫元数据驱动,或者低代码/零代码的底层思路。简单说,它把“表结构”从代码里抽出来,变成数据库里的一行行配置记录。

整个链路是这样的:在 sys_entity 表里注册一个实体,比如 customer(客户管理);在 sys_field 表里配置这个实体的字段,比如 customer_name、phone、status;小程序端列表页加载这些配置,自动渲染表头和搜索栏;表单页加载这些配置,自动渲染输入控件;服务端 CRUD 接口也读取这些配置,生成对应的增删改查逻辑。

所以新增一个“信息模块”在平台里本质上等于“插入一条实体配置 + 若干字段配置”,剩下的列表、表单、接口、权限,都是围绕配置动态生成的。我第一次看明白这个设计时,最大的感受是:原来“写代码”和“描述数据”是可以解耦的,后端接口不再是针对某一张表写死,而是针对“任意一张配置过的表”统一处理。

2.3 这样设计的得与失

配置驱动不是银弹,它有自己的成本和边界。先说得的部分:

  • 新增模块快。客户管理做完,再做供应商管理,就是复制一套字段配置的事。
  • 页面风格统一。所有模块共用同一套列表页和表单页,视觉和交互天然一致。
  • Bug 面小。通用逻辑只维护一份,修一次全体生效。
  • 后续可以长出可视化后台。既然配置都存数据库,那做一个 Web 管理界面去操作这些配置,只是时间问题。

再说代价:

  • 通用层必须做得足够保守。字段类型、校验规则、搜索逻辑都要抽象成统一模型,一旦某个需求超出模型,就得给平台开“后门”。
  • 复杂关联查询很吃力。涉及多表 join、聚合统计、动态条件组合时,通用 CRUD 的 SQL 拼接逻辑会变得很复杂,性能也不好控制。
  • 配置本身需要设计。字段的 label、type、必填、可搜索、可编辑,这些配置项也需要有人去规划,不是随意填的。

所以成熟的做法是:平台提供扩展点。比如注册自定义接口、自定义页面、字段级的事件钩子。通用层做 80% 的场景,剩下 20% 用扩展解决,这样平台才不会变成新的瓶颈。

3. 源码目录里最重要的三张表和三个入口文件

3.1 先看目录,别一上来就 npm install

很多朋友下载源码后第一件事就是 npm install,结果报错一堆,心情全无。我的习惯是先把目录结构通读一遍,搞清楚每个文件是干什么的,再动手跑。以下是这套平台常见的目录结构(不同版本可能有细微出入,以你下载到的源码为准):

mini-info-platform/ ├── miniprogram/ │ ├── pages/ │ │ ├── index/ # 工作台:模块入口列表 │ │ ├── list/ # 通用列表页:根据配置渲染搜索/列表 │ │ ├── detail/ # 通用详情页 │ │ ├── form/ # 通用表单页:新增/编辑共用 │ │ ├── login/ # 登录页 │ │ └── mine/ # 我的:个人信息/退出 │ ├── utils/ │ │ ├── request.js # 请求封装:baseURL、token、错误提示 │ │ └── util.js # 格式化、防抖等工具 │ ├── config.js # 接口地址、全局配置 │ ├── app.js │ └── app.json ├── server/ │ ├── routes/ │ │ ├── auth.js # 登录注册 │ │ ├── entity.js # 实体配置读取 │ │ ├── crud.js # 通用增删改查 │ │ └── user.js # 用户信息 │ ├── middlewares/ │ │ └── auth.js # JWT 校验 │ ├── utils/ │ │ └── db.js # mysql2 连接池 │ ├── app.js # Express 入口 │ └── config.js # 数据库/密钥/端口 └── sql/ └── init.sql # 系统表 + 示例业务表

看懂这个结构之后,你会发现小程序端的工作量其实很少:真正的页面只有 index、list、detail、form、login、mine 六个,业务模块都靠配置驱动,不需要为每个模块新开页面。服务端的关键是 routes/crud.js 和 routes/entity.js,前者是通用增删改查,后者是配置读取。

3.2 三张系统表:sys_user、sys_entity、sys_field 的作用

数据库初始化时会建好几张表,核心是下面这三张系统表:

表名作用关键字段
sys_user用户表id, username, password_hash, nickname, role
sys_entity业务实体配置id, entity_name, table_name, title, owner_field, status
sys_field字段配置id, entity_id, name, label, type, listable, searchable, editable, required, options_json, sort_order

sys_user 不用多说,做登录和权限控制。sys_entity 一行代表一个业务模块,比如 customer、goods、appointment。sys_field 是这个业务模块的字段定义,它决定了列表页显示哪些列、搜索框搜哪些字段、表单页有哪些输入项、哪些字段必填、哪些字段可选。

特别注意 options_json 这个字段,它用来存 select/radio 类型的候选项,比如“跟进状态:待跟进、跟进中、已成交”,在配置里是一段 JSON 字符串,前端解析后渲染成下拉选项。字段类型不一样,表单页渲染出来的控件也不一样:text 渲染输入框,textarea 渲染多行文本,date 渲染日期选择器,number 渲染数字输入框,image 渲染图片上传。

3.3 三个入口文件:config.js、app.js、request.js

跑通项目之前,先找到三个入口文件,它们是你改动最多的地方。

第一个是 server/config.js,里面是数据库连接信息、JWT 密钥、服务端口。拿到源码后第一件事就是把数据库账号密码改成你自己的,把 JWT_SECRET 从默认值换掉。JWT 密钥是登录态签名的关键,用默认值等于把后门开着。

第二个是 server/app.js,Express 的入口文件。它会挂载 body 解析中间件、路由、静态资源、404 兜底。在这里你能看清整个服务端暴露了哪些接口,中间件的加载顺序是什么样的,排查报错时第一个看它。

第三个是 miniprogram/utils/request.js,小程序端的请求封装。它统一管理 baseURL、token 注入、响应拦截、错误提示。你本地联调时改的就是这个文件的 baseURL,改成 http://127.0.0.1:3000 还是局域网 IP,决定了你能不能调通。

4. 跑通全流程:从空目录到手机里能用的信息模块

4.1 环境准备清单

跑这套平台之前,先把环境准备好,避免中途来回折腾:

组件建议版本作用
Node.js16 LTS,不低于 14运行服务端
MySQL5.7 或 8.0存储数据
小程序开发者工具最新稳定版开发/预览小程序
Git可选,建议装拉取/管理源码

Node.js 版本太老会报语法错误,Express 4 不太挑版本,但 mysql2 连接库对老版本 Node 的兼容性一般,所以推荐 16 LTS。数据库安装时字符集选 utf8mb4,如果建库时用了默认的 latin1,后面存中文会发现乱码,排查半天最后才发现是字符集问题,太亏了。

4.2 初始化数据库:init.sql 里到底做了什么

数据库初始化很简单,两行命令:

mysql -u root -p -e "CREATE DATABASE IF NOT EXISTS mini_info_dev DEFAULT CHARACTER SET utf8mb4;" mysql -u root -p mini_info_dev < sql/init.sql

第一行创建数据库,指定 utf8mb4 字符集;第二行导入初始化脚本。init.sql 做的事有三件:建系统表 sys_user、sys_entity、sys_field;插入一个示例实体 customer 及其字段配置;插入一个初始管理员账号,密码是哈希值,源码包里一般会写明初始密码,登录后务必改掉。

导入完成后可以用下面命令确认表建好了:

mysql -u root -p mini_info_dev -e "SHOW TABLES;"

你会看到系统表之外,还有一张 customer 业务表,这张表示例用的。如果后面你通过注册实体新增模块,服务端会自动创建对应的业务表,前提是 MySQL 账号有 CREATE 权限,这个坑后面专门说。

4.3 启动服务端:完整步骤和第一屏日志

服务端启动命令很简单:

cd server npm install node app.js

npm install 可能因为网络原因比较慢,如果卡住可以换镜像源。启动成功后会看到类似这样的日志:

Server running at http://0.0.0.0:3000 MySQL connected

看到这两行就说明服务端起来了。最常见的两个报错:一是 3306 端口连不上,检查 MySQL 服务是否启动、config.js 里的账号密码是否正确;二是端口冲突,3000 被别的进程占了,改 config.js 里的 PORT 即可。

生产环境我建议用 pm2 管理进程:pm2 start app.js --name mini-info-server,这样崩溃了会自动拉起,重启服务器也能开机自启。

4.4 小程序端联调:从开发者工具到真机预览

服务端跑起来后,用小程序开发者工具导入 miniprogram 目录,修改 utils/request.js 里的 baseURL,就能开始联调。不同阶段 baseURL 的配置完全不一样:

运行场景baseURL 示例合法域名备注
开发者工具调试http://127.0.0.1:3000不需要,可勾选“不校验合法域名”最快验证
真机预览http://192.168.x.x:3000不需要,预览版可用开发环境手机和电脑须同一局域网
线上发布https://api.example.com必须配置并校验必须 HTTPS

这里有个很容易踩的坑:开发者工具里用 http://127.0.0.1:3000 调通了,真机预览却白屏。因为在手机上,127.0.0.1 指向的是手机自己,不是你的电脑。真机预览必须把 baseURL 改成电脑的局域网 IP,比如 http://192.168.1.100:3000,同时手机和电脑连同一个 Wi-Fi。如果不在同一网段,要么内网穿透,要么直接把服务端部署到有公网 IP 的服务器上,然后走合法域名那条路。

5. 通用增删改查的核心代码:把CRUD变成配置项

5.1 列表接口:分页、搜索、用户数据隔离的一次成型

平台最核心的文件是 server/routes/crud.js。它不是针对某张表写的,而是通用的“任意实体 CRUD”。我们看列表接口的实现思路,我把关键代码简化了一下:

const express = require('express'); const router = express.Router(); const auth = require('../middlewares/auth'); const db = require('../utils/db'); // 根据实体名读取配置 async function getEntity(entityName) { const [rows] = await db.query('SELECT * FROM sys_entity WHERE entity_name = ? AND status = 1', [entityName]); if (!rows.length) return null; const entity = rows[0]; const [fields] = await db.query('SELECT * FROM sys_field WHERE entity_id = ? ORDER BY sort_order', [entity.id]); entity.fields = fields; return entity; } // GET /api/crud/:entityName?page=1&pageSize=10&keyword=xx router.get('/:entityName', auth, async (req, res) => { const entity = await getEntity(req.params.entityName); if (!entity) return res.status(404).json({ message: '实体不存在' }); const { page = 1, pageSize = 10, keyword = '' } = req.query; const where = []; const params = []; // 数据隔离:配置了 owner_field 的实体,非管理员只能看自己创建的数据 if (entity.owner_field && req.user.role !== 'admin') { where.push(`\`${entity.owner_field}\` = ?`); params.push(req.user.id); } // 模糊搜索:只搜配置里 searchable 的字段 if (keyword) { const likeFields = entity.fields.filter(f => f.searchable); if (likeFields.length) { const likeClause = likeFields.map(f => `\`${f.name}\` LIKE ?`).join(' OR '); where.push(`(${likeClause})`); likeFields.forEach(() => params.push(`%${keyword}%`)); } } const whereSql = where.length ? `WHERE ${where.join(' AND ')}` : ''; const [count] = await db.query(`SELECT COUNT(*) AS total FROM \`${entity.table_name}\` ${whereSql}`, params); const [rows] = await db.query( `SELECT * FROM \`${entity.table_name}\` ${whereSql} ORDER BY id DESC LIMIT ? OFFSET ?`, [...params, Number(pageSize), (Number(page) - 1) * Number(pageSize)] ); res.json({ code: 0, data: { list: rows, total: count[0].total } }); }); module.exports = router;

这段代码看起来很普通,但有几个关键点值得注意:

  • 表名和字段名都用了反引号包裹,防止保留字和注入问题。
  • 值全部走参数化查询,不要直接拼 SQL 字符串。
  • 搜索只作用于配置里 searchable 的字段,而不是把所有字段都 LIKE 一遍,否则数据量一大性能就会出问题。
  • owner_field 的自动拼接实现了“用户只能看到自己的数据”,这个逻辑对所有实体通用,新增实体时只要配置 owner_field 字段,就自动获得数据隔离能力。

5.2 创建与更新:字段白名单与防注入

新增接口的精髓是“字段白名单”。前端传什么不是重点,重点是这个实体配置里允许写哪些字段。简化代码如下:

router.post('/:entityName', auth, async (req, res) => { const entity = await getEntity(req.params.entityName); if (!entity) return res.status(404).json({ message: '实体不存在' }); const payload = {}; for (const field of entity.fields) { if (!field.editable) continue; // 必填校验 if (field.required && req.body[field.name] === undefined) { return res.status(400).json({ message: `缺少必填字段: ${field.label}` }); } if (req.body[field.name] !== undefined) { payload[field.name] = req.body[field.name]; } } // 自动注入创建人 if (entity.owner_field) { payload[entity.owner_field] = req.user.id; } const [result] = await db.query(`INSERT INTO \`${entity.table_name}\` SET ?`, payload); res.json({ code: 0, data: { id: result.insertId } }); });

这段代码的用意很明显:即使有人恶意 POST 一个不存在的字段,也会被配置过滤掉。更新接口同理,但必须带上 ID 条件,并且要校验这条记录的 owner_field 是不是当前用户,防止越权修改别人的数据。我用白名单 + 参数化查询,基本堵住了最常见的注入和越权漏洞。

5.3 前端列表页和表单页的动态渲染原理

前端之所以能做到“新增模块不需要新开页面”,核心是页面不关心具体字段,只关心配置。

列表页的 WXML 里没有写死任何列名,而是通过 wx:for 遍历一个columns数组:

<view class="list-header"> <view wx:for="{{columns}}" wx:key="name" class="col-{{index}}"> {{item.label}} </view> </view> <view class="list-row" wx:for="{{list}}" wx:key="id"> <view wx:for="{{columns}}" wx:key="name" class="col-{{index}}"> {{item.type === 'select' ? formatSelect(row[item.name], item.options) : row[item.name]}} </view> </view>

columns 的数据来自/api/entity/:entityName接口,它读取 sys_field 配置后返回 name、label、type、options 等信息。页面加载配置后,再去请求列表数据,然后渲染。新增或编辑时,表单页根据 field.type 决定渲染什么控件:text 是输入框,textarea 是文本域,date 是日期选择器,select 是下拉选择,image 是上传组件。

这样做的好处是,以后新增模块你只需要配数据,不需要碰页面代码。代价是,动态渲染一个表单字段时,要记得给 dataForm 里每个字段初始化默认值;如果字段很多,setData 的数据量会偏大,建议对 columns 做裁剪,列表只取 listable 的字段,表单一次只渲染当前分组的字段。

5.4 用配置实现一个“客户管理”模块,要改哪几处

假设现在要新增一个“客户管理”模块,在配置驱动下你只需要做两件事:

第一,往 sys_entity 插入一行配置:

entity_nametable_nametitleowner_field
customercustomer客户管理create_by

第二,往 sys_field 插入字段配置:

namelabeltypelistablesearchableeditablerequiredoptions_json
customer_name客户名称text1111null
contact联系人text1010null
phone联系电话text1010null
status跟进状态select1111["待跟进","跟进中","已成交"]
remark备注textarea0010null

插入完成后,如果 customer 业务表不存在,服务端注册实体时会自动建表。小程序端重新进入工作台,就会出现“客户管理”入口,点进去就是完整的列表、搜索、新增、编辑、详情、删除功能。整个过程不需要写一行业务代码,这就是配置驱动的直观体验。

6. 同一份源码,不同的坑:我的实测踩坑记录

6.1 开发者工具正常、真机白屏:域名白名单问题

这个坑我几乎每次联调都会遇到,新手最容易卡住。现象是:开发者工具里页面正常加载,数据也能请求到,但手机扫码预览后白屏或者接口全部报错。

排查思路:

  • 先看控制台报错,如果提示 “request:fail”,基本就是网络请求没到达服务器。
  • 确认 baseURL 是不是写的 127.0.0.1 或 localhost,在手机里这两个地址指向手机自己。
  • 把 baseURL 改成电脑局域网 IP,确认手机和电脑在同一 Wi-Fi 下。
  • 如果手机还是连不通,检查电脑防火墙有没有放行 3000 端口,Windows 经常会拦截。

另外,正式发布时要求 HTTPS 和合法域名,本地“不校验合法域名”这个选项只能在开发者工具里用,真机预览不一定生效。最稳妥的方案是:本地开发用开发者工具 + 127.0.0.1;真机体验用内网穿透或局域网 IP;正式上线走配置好的 HTTPS 域名。

6.2 数据库的 DDL 权限与连接池

这个坑藏得很深。平台的核心是“注册实体时自动建表”,这在本地开发没问题,但部署到某些虚拟主机或云数据库时,业务账号可能只有 DML 权限,没有 CREATE/ALTER 权限。结果就是:配置实体的时候,接口报CREATE command denied,数据库里查不到业务表。

解决办法有两类:一是给数据库账号补上 DDL 权限,适合自建服务器;二是把建表动作从应用里拆出来,把平台要用的业务表提前在 init.sql 里建好,应用运行时只做 DML。生产环境我推荐后者,更可控,也符合最小权限原则。

再说连接池。默认配置里 mysql2 连接池的 max 可能写得比较大,比如 50。想象一个场景:小程序端每个页面加载都要请求配置接口和 CRUD 接口,如果连接池瞬间把 MySQL 的连接数拉满,数据库会直接报Too many connections。我实际测试下来的经验是,中小型项目连接池 max 设置在 10 到 20 之间足够了,连接池是复用连接,不是并发线程池,开太多反而浪费数据库资源。

6.3 日期时间字段的格式陷阱

信息管理模块里几乎都离不开日期:预约时间、生日、创建时间、到期时间。这里有两个坑:

第一个是 MySQL 的 TIMESTAMP 和 DATETIME 选择。TIMESTAMP 的范围是 1970 年到 2038 年,如果你做的是会员生日、历史档案这类要存过去日期的功能,建议统一用 DATETIME。DATETIME 没有时区转换逻辑,存什么就是什么,对大多数单机部署的应用来说更省心。

第二个是前端日期组件的兼容性。小程序原生的 picker 组件,date 模式要求 value 格式必须是YYYY-MM-DD,但在部分 Android 机型上,如果你用new Date()去构造日期,得到的结果可能是Invalid Date。我踩过的坑是:后端存的日期是2024-05-01 10:30:00,前端直接用这个字符串去初始化 picker,iOS 正常,Android 白屏。解决方式很简单,前端做一次格式化,只取年月日部分拼成YYYY-MM-DD,再传给 picker。

6.4 并发编辑导致数据被覆盖

平台自带的更新接口是“读出来改完再保存”,没有版本控制。两个人同时打开同一条客户记录,A 改了电话先保存,B 改完备注再保存,B 保存时会把 A 的修改覆盖掉。这在团队协作场景里是致命的。

解决办法是加乐观锁。业务表加一个version字段,默认值是 1。更新时 SQL 写成:

UPDATE customer SET phone = ?, version = version + 1 WHERE id = ? AND version = ?;

如果更新影响的行数为 0,说明这条记录已经被别人改过了,接口返回“数据已被他人修改,请刷新后重试”。前端拿到这个提示后,刷新列表或详情让用户重新编辑。这个改造不复杂,但能避免绝大多数“数据莫名其妙消失”的投诉。

7. 如果让我继续改造这个平台,我会从这三件事开始

7.1 可视化配置后台,让运营同事自己建模块

平台目前的配置入口是数据库表,只有懂 SQL 的人能操作。要让它真正成为一个“平台”,下一步应该做一个 Web 管理后台:左边列出所有实体,右边展示字段配置,支持新增实体、拖拽调整字段顺序、配置必填和搜索项。

后端接口其实早就准备好了,操作 sys_entity 和 sys_field 就是普通的增删改查。前端用 Vue 或 React 写一个简单的表格页 + 表单页就能搞定。这个后台做完之后,业务人员自己就能建模块,开发者的工作只剩“查缺补漏”。

7.2 补上导出与基础报表

信息管理系统的用户有个共性:数据录进去之后,一定要导出来。Excel 是他们最熟悉的消费方式。目前平台的列表接口是分页的,不适合直接导出,需要加一个导出接口:

GET /api/crud/:entityName/export?type=csv&keyword=xx

服务端用流式输出 CSV,前端列表页加一个“导出当前筛选结果”按钮,把当前搜索条件传给导出接口,下载文件。数据量不大可以直接一次性导出,数据量大就做成异步任务,生成文件后通知用户下载。

报表可以做能力扩展:在实体配置里加一个统计字段的配置,前端配合图表组件画柱状图、饼图,对信息管理类系统来说,“每周新增客户数”“各状态订单占比”这类统计很常见,也很有价值。

7.3 多租户隔离:从 owner_field 到 tenant_id

owner_field 解决的是“用户只能看自己的数据”,但对 B 端场景还不够:一个企业有 10 个员工,他们需要共享企业内的客户数据,同时不同企业之间的数据要隔离。这时候就要引入租户维度。

具体改造思路:给 sys_entity、sys_user、所有业务表都加一个tenant_id字段,服务端在写入数据时自动注入当前用户的 tenant_id,查询时自动拼接tenant_id = ?条件。索引也要加上,tenant_id 和 create_by 的联合索引基本能覆盖绝大多数查询。这个改造不复杂,但要注意所有接口的 SQL 都要统一走这个约束,漏掉一个就是数据越权。

如果你只有几个内部团队使用,可以做简化版:把 tenant_id 的配置做成可选,不填就退化成现在的 owner_field 模式,填了就启用多租户隔离。

最后说点务虚的体会

这套“含源码”的信息管理小程序开发平台,能跑通只算入门,真正考验人的是理解它的设计边界。我拿它改造时最大的收获,不是省下的那几天开发时间,而是养成一个习惯:接到一个新需求,先想“这个模块能不能用配置描述出来”,而不是直接动手建表写接口。把数据结构定义清楚,把字段清单列明白,剩下的增删改查,其实是水到渠成的事。你手上的源码可能跟我在文中描述的有细节出入,但思路是通的——通用的骨架加上配置化的扩展点,足够你应对大部分信息管理类的小程序需求。下载源码之后,先把架构和配置表吃透,再动手加模块,你会少踩很多坑。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询