子表单场景指南
前言
子表单场景用于处理一对多的数据录入需求,例如商品分类表单中需要录入多个商品信息,每个商品包含多个字段(如商品名称、价格等)。为了高效管理数据,通常将分类和商品分别存储在不同的表中,并通过关联关系进行绑定。
在页面提交时,需要完成以下操作:
- 更新主表数据
- 新增、更新或删除子表数据
- 更新主表与子表之间的关联关系
由于涉及多次数据库交互,建议使用 云函数 来实现这一逻辑,前端只需调用云函数即可完成数据更新。
实现思路
子表单场景的实现可分为以下步骤:
- 处理子表单数据
- 获取新增的子表数据
- 获取需要更新的子表数据
- 获取需要删除的子表数据
- 更新子表数据
- 更新主表数据
- 更新主表数据
- 更新主表与子表的关联关系
云函数开发
新建云函数
进入 云函数 模块,新建名为 subTable-management
的云函数,进入代码编辑器后,在上方工具栏找到「终端/新建终端」,执行如下命令初始化项目:
npm init -y
npm install @cloudbase/node-sdk
⚠️ 注意:终端路径需要在当前云函数目录下
编写代码
云函数需要接收以下参数:
mainName
:主表数据模型名称mainData
:主表数据subList
:子表数据(数组)subCode
:子表在主表中的编码subName
:子表数据模型名称subData
:子表当前数据subOldData
:子表源数据
isProd
:是否是生产环境
核心逻辑
- 对比子表数据:通过
diffSubData
函数比对 子表初始数据 和 子表当前数据,获取新增、更新和删除的数据。 - 执行子表操作:通过
executeSubTableOperations
方法执行子表数据的增删改操作。 - 更新主表数据:更新主表数据及其与子表的关联关系。
代码框架如下:
const cloudbase = require('@cloudbase/node-sdk');
const app = cloudbase.init({
env: cloudbase.SYMBOL_CURRENT_ENV,
});
const models = app.models;
/**
* 处理主表与子表数据关系
* @param {string} mainName - 主表数据模型名称
* @param {object} mainData - 主表数据
* @param {array} subList - 子表列表,每个元素包含子表信息
* @param {string} subList[].subCode - 子表在主表中的编码
* @param {string} subList[].subName - 子表数据模型名称
* @param {array} subList[].subData - 子表当前数据
* @param {array} subList[].subOldData - 子表源数据
* @param {boolean} isProd - 是否是生产环境
* @returns {Promise<object>} 处理结果
*/
exports.main = async function({
mainName,
mainData,
subList,
isProd = false,
}) {
try {
for (const subItem of subList) {
const {
subCode,
subName,
subData,
subOldData
} = subItem;
// 1. 对比子表数据,获取增删改操作
const {
addData,
updateData,
deleteIds
} = diffSubData(subData, subOldData);
// 2. 执行子表数据的增删改操作
const subRes = await executeSubTableOperations(subName, addData, updateData, deleteIds);
}
// 3. 更新主表数据
// ...
return {
success: true,
message: '数据处理成功',
details: {
subRes,
res,
},
};
} catch (error) {
console.error('数据处理失败:', error);
throw new Error(`数据处理失败: ${error.message}`);
}
};
完整代码示例请参考:GitHub 示例
部署云函数
点击「保存并安装依赖」,即可完成云函数的部署
页面开发
这里以「采购管理」系统为例,演示如何使用子表功能
我们以如下关系为例:
新建数据模型
进入 数据模型 新建如下三个数据模型:
采购订单(purchase_order)
字段名 | 类型 | 描述 |
---|---|---|
name | 文本 | 订单名称 |
amount | 数字 | 总金额 |
status | 枚举 | 订单状态 |
order_list | 关联关系(一对多) | 采购商品列表 |
supplier | 关联关系(多对一) | 供应商 |
order_list(采购订单) 和 purchase_item(采购商品明细) 字段类型为 关联关系
supplier(采购订单) 和 purchase_list(供应商联系人) 字段类型为 关联关系
采购商品明细(order_items)
字段名 | 类型 | 描述 |
---|---|---|
name | string | 商品名称 |
price | number | 商品价格 |
quantity | number | 采购数量 |
purchase_item | 关联关系(多对一) | 所属订单 |
供应商联系人(supplier_contacts)
字段名 | 类型 | 描述 |
---|---|---|
name | string | 联系人姓名 |
phone | number | 联系电话 |
purchase_list | 关联关系(一对多) | 订单列表 |
新增应用
新建一个空白应用,通过模板快速生成「表格与表单页」,数据模型选择 采购订单(purchase_order)
修改编辑页
进入编辑页面,由于表单容器绑定数据源方式并不能拿到子表完整数据,所以这里需要修改表单容器的数据源
页面新建内置数据表查询
在当前页面新增一个「内置数据表查询」方法,命名为 getOrderDetail
- 配置数据表为:采购订单(purchase_order)
- 触发方式为:手动触发执行
- 查询条件为:数据标识 等于 $w.page.dataset.params._id(url传过来的_id)
- 关联表查询选择 (对象):返回采购商品列表关联表、返回供应商关联表
此时点击「运行」按钮可以看到数据中 splb字段返回了完整的商品列表数据
页面添加加载事件
在页面级页面加载事件中加入如下 JS 代码,用来控制仅编辑时才触发查询
// 通过内置数据表查询获取数据
({
event
}) => {
if ($w.page.dataset.params.formType === 'edit') {
$w.getOrderDetail.trigger()
}
}
修改表单容器数据源
修改表单容器的数据源为:表达式
切换时会提示 「此操作将会重新生成/清空表单组件,是否需要重新生成/清空?」,选择 否
表达式内容为「内置数据表查询」结果
$w.page.dataset.params.formType === 'edit' ? {
...$w.getOrderDetail.data,
supplier: $w.getOrderDetail.data.supplier?._id
} : {}
supplier 赋值原因是因为该字段为多对一,在 getOrderDetail 方法中是以完整数据对象返回,因此需要取出 _id 用以回填组件
修改商品列表组件
商品列表 组件默认是 下拉框,这里我们修改为 数组嵌套表单 组件
- 修改 嵌套表单模板 为 对象数组(表格)
- 修改 绑定字段 为 order_list
- 添加子表字段:
- 商品名称(name)(文本字段)
- 采购数量(quantity)(数字输入)
- 商品价格(price)(数字输入)
修改提交事件
接下来查看「表单容器」的提交事件,其中调用了「数据源方法」进行更新数据
此时我们需要将其改成上章节新增的 云函数 去完成数据入库
因此我们切换「调用数据源方法」为「调用云函数方法」,并写下如下脚本,即可完成主子表的数据更新,云函数参数参考 上一章节
async () => {
await $w.cloud.callFunction({
name: 'subTable-management',
data: {
mainName: 'purchase_order',
mainData: {
...$w.form1.value,
_id: $w.page.dataset.params._id,
// 其他非子表单的关联关系字段需要单独处理
supplier: {
_id: $w.form1.value.supplier
}
},
subList: [{
subCode: 'order_list',
subName: 'order_items',
subData: $w.form1.value?.splb || [],
subOldData: $w.form1.remoteValue?.splb || [],
}]
},
});
};
mainData 中需要带上 _id,以及其他非子表单的关联关系字段数据
$w.form1.remoteValue
是 form1 表单容器 组件的初始值
示例项目链接:采购订单管理系统
总结
通过云函数和页面开发的结合,可以高效实现子表单场景的数据管理。云函数负责处理复杂的数据库操作,前端只需调用云函数即可完成数据更新,确保逻辑清晰且性能优化。