跳到主要内容

子表单场景指南

前言

子表单场景用于处理一对多的数据录入需求,例如商品分类表单中需要录入多个商品信息,每个商品包含多个字段(如商品名称、价格等)。为了高效管理数据,通常将分类和商品分别存储在不同的表中,并通过关联关系进行绑定。

在页面提交时,需要完成以下操作:

  1. 更新主表数据
  2. 新增、更新或删除子表数据
  3. 更新主表与子表之间的关联关系

由于涉及多次数据库交互,建议使用 云函数 来实现这一逻辑,前端只需调用云函数即可完成数据更新。

实现思路

子表单场景的实现可分为以下步骤:

  1. 处理子表单数据
    • 获取新增的子表数据
    • 获取需要更新的子表数据
    • 获取需要删除的子表数据
    • 更新子表数据
  2. 更新主表数据
    • 更新主表数据
    • 更新主表与子表的关联关系

云函数开发

新建云函数

进入 云函数 模块,新建名为 subTable-management 的云函数,进入代码编辑器后,在上方工具栏找到「终端/新建终端」,执行如下命令初始化项目:

npm init -y

npm install @cloudbase/node-sdk

⚠️ 注意:终端路径需要在当前云函数目录下

编写代码

云函数需要接收以下参数:

  • mainName:主表数据模型名称
  • mainData:主表数据
  • subList:子表数据(数组)
    • subCode:子表在主表中的编码
    • subName:子表数据模型名称
    • subData:子表当前数据
    • subOldData:子表源数据
  • isProd:是否是生产环境

核心逻辑

  1. 对比子表数据:通过 diffSubData 函数比对 子表初始数据子表当前数据,获取新增、更新和删除的数据。
  2. 执行子表操作:通过 executeSubTableOperations 方法执行子表数据的增删改操作。
  3. 更新主表数据:更新主表数据及其与子表的关联关系。

代码框架如下:

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)

字段名类型描述
namestring商品名称
pricenumber商品价格
quantitynumber采购数量
purchase_item关联关系(多对一)所属订单

供应商联系人(supplier_contacts)

字段名类型描述
namestring联系人姓名
phonenumber联系电话
purchase_list关联关系(一对多)订单列表

新增应用

新建一个空白应用,通过模板快速生成「表格与表单页」,数据模型选择 采购订单(purchase_order)

修改编辑页

进入编辑页面,由于表单容器绑定数据源方式并不能拿到子表完整数据,所以这里需要修改表单容器的数据源

页面新建内置数据表查询

在当前页面新增一个「内置数据表查询」方法,命名为 getOrderDetail

  1. 配置数据表为:采购订单(purchase_order)
  2. 触发方式为:手动触发执行
  3. 查询条件为:数据标识 等于 $w.page.dataset.params._id(url传过来的_id)
  4. 关联表查询选择 (对象):返回采购商品列表关联表返回供应商关联表

此时点击「运行」按钮可以看到数据中 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 用以回填组件

修改商品列表组件

商品列表 组件默认是 下拉框,这里我们修改为 数组嵌套表单 组件

  1. 修改 嵌套表单模板对象数组(表格)
  2. 修改 绑定字段order_list
  3. 添加子表字段:
    • 商品名称(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.remoteValueform1 表单容器 组件的初始值

示例项目链接:采购订单管理系统

总结

通过云函数和页面开发的结合,可以高效实现子表单场景的数据管理。云函数负责处理复杂的数据库操作,前端只需调用云函数即可完成数据更新,确保逻辑清晰且性能优化。