聚合表场景应用
在搭建宜搭应用的过程中,你可能会遇到以下这些问题。
- 会议室预约: 在预约会议室的场景中,可能会遇到多人同时预约同一会议室且时间重叠的问题,从而导致预约冲突。通过使用聚合表,可以有效管理并解决这类预约异常问题,确保资源得到合理分配。
- 活动报名:在活动报名场景中,高并发可能会导致超额报名的问题。为了解决这一问题,可以在聚合表中设置校验规则:每位参与者只能预约一次(即预约次数应小于或等于1),这样可以有效避免超报现象的发生。
- 进销存:制造业、零售业、建筑行业等所有涉及到实物库存管理的都需要一套库存管理系统去实现对出库、入库、调拨、盘点的全流程管理,实现精准把控企业的库存数据,基于库存数据去合理安排销售计划、采购计划、生产计划。使用聚合表,通过出库入业务表单,计算产品的实时库存,并在出入库业务表单提交、或审批的时候,实时进行校验,如果出库数量大于库存剩余数量,则校验不允许超卖。
前提条件
本教程使用到宜搭部分基础功能,你可以先了解以下功能。
实现效果
会议室预约
当多人尝试预约同一会议室且时间重叠时,系统将自动阻止新的预约请求。

活动报名
当同时选中同一活动进行报名时,系统将实时校验当前剩余可报名人数,若报名满额将自动阻断本次报名。

进销存
涉及到同时出库同种产品时,系统将实时校验库存表当前库存数,若出现库存不足时,将自动阻断本次出库。

实现步骤
会议室预约
创建表单
创建【会议室信息】页面,详情请参考普通表单。

在画布区域拖入以下组件。
- 单行文本:命名为会议室名称
- 多行文本:命名为会议室地址
创建【会议室预约】页面,详情请参考流程表单。

在画布区域拖入以下组件。
- 关联表单:命名为选择会议室,关联【会议室信息】
- 日期:命名为开始时间
- 下拉单选:命名为开始时分
- 日期:命名为结束时间
- 下拉单选:命名为结束时分
- 子表单:命名为预约时间段
- 单行文本:命名为会议室名称
- 单行文本:命名为年月日
- 单行文本:命名为时分
- 数值:预约次数,默认值为 1
- 日期:命名为预约开始时间
- 日期:命名为预约结束时间
- 单行文本:命名为会议室名称
预约会议室时间段重叠处理
开始时间绑定事件,获取当前所选会议室已预约时间段

// 选择会议室 onChange
export function onMeetingRoomChange({ value }) {
this.$('dateField_lld25jg9').reset();
this.$('dateField_lld25jgc').reset();
}
// 开始时间 onChange
export function onStartTimeChange({ value }) {
this.$('selectField_lld25jga').reset();
if (value) {
this.utils.yida.searchFormDatas({
formUuid: 'FORM-8A474E900003479FAFFED91C314B7A49WXAM',
pageSize: 100,
searchFieldJson: JSON.stringify({
textField_m42hvwgu: this.$('textField_m42j2c2j').getValue(),
textField_m42hvwgv: this.utils.formatter('date', value, 'YYYY-MM-DD'),
}), // 可以根据组件值查询
}).then((res) => {
const { data = [] } = res;
const noAllowTimeCurrent = data.map(({ formData = {} }) => {
return formData.textField_m42hvwgw;
});
this.$('selectField_lld25jga').set('dataSource', this.setTimeCurrent().map((item) => {
return {
...item,
disabled: noAllowTimeCurrent.includes(item.value),
};
}));
});
} else {
this.$('selectField_lld25jga').set('dataSource', []);
}
}
// 开始时分 onChange
export function onStartTimeCurrentChange({ value, actionType, item }) {
if (value) {
this.$('dateField_m42j2c2f').setValue(new Date(`${this.utils.formatter('date', this.$('dateField_lld25jg9').getValue(), 'YYYY-MM-DD')} ${value}:00`).getTime());
} else {
this.$('dateField_m42j2c2f').reset();
}
}
「结束时间」、「结束时分」绑定事件,处理数据。

// 结束时间 onChange
export function onEndTimeChange({ value }) {
this.$('selectField_lld25jge').reset();
if (value) {
this.utils.yida.searchFormDatas({
formUuid: 'FORM-8A474E900003479FAFFED91C314B7A49WXAM',
pageSize: 100,
searchFieldJson: JSON.stringify({
textField_m42hvwgu: this.$('textField_m42j2c2j').getValue(),
textField_m42hvwgv: this.utils.formatter('date', value, 'YYYY-MM-DD'),
}), // 可以根据组件值查询
}).then((res) => {
const { data = [] } = res;
const noAllowTimeCurrent = data.map(({ formData = {} }) => {
return formData.textField_m42hvwgw;
});
this.$('selectField_lld25jge').set('dataSource', this.setTimeCurrent().map((item) => {
return {
...item,
disabled: noAllowTimeCurrent.includes(item.value),
};
}));
});
} else {
this.$('selectField_lld25jge').set('dataSource', []);
}
}
// 结束时分 onChange
export function onEndTimeCurrentChange({ value, actionType, item }) {
if (value) {
this.$('dateField_m42j2c2g').setValue(new Date(`${this.utils.formatter('date', this.$('dateField_lld25jgc').getValue(), 'YYYY-MM-DD')} ${value}:00`).getTime());
} else {
this.$('dateField_m42j2c2g').reset();
}
}
系统字段「预约开始时间」、「预约结束时间」处理预约时间段数据赋值给预约时间段子表单。

export function solveTimeCurrent() {
const meetingRoomName = this.$('textField_m42j2c2j').getValue(); // 会议室名称
const startTime = this.$('dateField_m42j2c2f').getValue(); // 预约开始时间
const endTime = this.$('dateField_m42j2c2g').getValue(); // 预约结束时间
const { intervalTime } = this.state; // 间隔时间
if (meetingRoomName && startTime && endTime) {
const tableFieldValue = [];
for (let i = startTime; i <= endTime; i += (intervalTime * 60000)) {
tableFieldValue.push({
textField_m42gqpjl: meetingRoomName,
textField_m42gqpjg: this.utils.formatter('date', i, 'YYYY-MM-DD'),
textField_m42hdjiy: this.utils.formatter('date', i, 'hh:mm'),
numberField_m42gqpji: 1,
});
}
this.$('tableField_m42gqpjf').setValue(tableFieldValue);
} else {
this.$('tableField_m42gqpjf').reset();
}
}
/**
* 获取时分段
* @param startHour {Number} 开始小时数
* @param endHour {Number} 结束小时数
* @param intervalTime {Number} 间隔分钟数,15、30、60
*/
export function setTimeCurrent(startHour = 8, endHour = 20, intervalTime = this.state.intervalTime) {
const dayStart = new Date().setHours(startHour, 0, 0, 0);
const dayEnd = new Date().setHours(endHour, 0, 0, 0);
const timeCurrent = [];
for (let i = dayStart; i <= dayEnd; i += (intervalTime * 60000)) {
timeCurrent.push({
text: this.utils.formatter('date', i, 'hh:mm'),
value: this.utils.formatter('date', i, 'hh:mm'),
});
}
return timeCurrent;
}
提交会议室预约申请数据前,校验预约结束时间不得早于预约开始时间

// 表单提交前
export function beforeSubmit({ formDataMap }) {
return new Promise((resolve) => {
const startTime = this.$('dateField_m42j2c2f').getValue(); // 预约开始时间
const endTime = this.$('dateField_m42j2c2g').getValue(); // 预约结束时间
if (startTime >= endTime) {
this.utils.toast({
title: '预约开始时间需小于预约结束时间,请重新选择',
type: 'error',
});
resolve(false);
}
resolve(true);
});
}
创建【会议室预约记录】聚合表
选择数据源【会议室预约】,配置「关联关系」分别为会议室名称、年月日、时分。

配置「列标题」:

配置「指标」:

配置「提交校验」:

{"text":"预约次数<=1","marks":[{"from":{"line":0,"ch":0,"sticky":null},"to":{"line":0,"ch":6,"sticky":null},"value":"numberField_m42h3qm5","invalid":false}],"isCmData":true}
保存发布聚合表

活动报名
创建表单
创建【活动信息】表单,详情请参考普通表单。

在画布区域拖入以下组件。
- 单行文本:命名为活动名称
- 数值:命名为可报名人数
- 单行文本:命名为举办地点
- 日期:命名为举办日期
创建【活动报名】表单,详情请参考普通表单。

在画布区域拖入以下组件。
- 关联表单:命名为选择活动,关联【活动信息】表单
- 数值:命名为剩余可报名人数
- 数值:命名为已报名人数
- 数值:命名为可报名人数
- 单行文本:命名为活动名称
- 数值:命名为报名人数,默认值为1
创建【剩余/已报名人数】聚合表
选择数据源【活动信息】、【活动报名】两张表单,并配置「关联关系」为活动名称字段。

配置「列标题」,字段为活动名称:

配置「指标」:

「剩余可报名人数」公式配置:

{"text":"活动信息.可报名人数-活动报名.报名人数","marks":[{"from":{"line":0,"ch":0,"sticky":null},"to":{"line":0,"ch":12,"sticky":null},"value":"FORM-5CA60EB4747F4B3093D37FC7E52CC8EFECFX/numberField_m46eaw05","invalid":false},{"from":{"line":0,"ch":13,"sticky":null},"to":{"line":0,"ch":24,"sticky":null},"value":"FORM-92C18462081648628EF6E01D5CEA6CD6FPLP/numberField_m46ejo1z","invalid":false}],"isCmData":true}
配置「提交校验」:

{"text":"剩余可报名人数>=0","marks":[{"from":{"line":0,"ch":0,"sticky":null},"to":{"line":0,"ch":9,"sticky":null},"value":"numberField_m46ejzhb","invalid":false}],"isCmData":true}
保存发布聚合表

进销存
创建表单
创建【产品信息】表单,详情请参考普通表单。

在画布区域拖入以下组件。
- 单行文本:命名为产品名称
- 单行文本:命名为规格
创建【入库表】表单,详情请参考普通表单。

在画布区域拖入以下组件。
- 成员:命名为操作人,默认当前登录人
- 日期:命名为入库日期,默认当前时间
- 子表单:命名为入库清单
- 关联表单:命名为入库产品,关联【产品信息】表单
- 数值:命名为入库数量
- 单行文本:命名为入库产品名称,由「入库产品」填充
- 数值:命名为当前库存数量,数据联动【库存信息】聚合表
创建【出库表】表单,详情请参考普通表单。

在画布区域拖入以下组件。
- 成员:命名为操作人,默认当前登录人
- 日期:命名为出库日期,默认当前时间
- 子表单:命名为出库清单
- 关联表单:命名为出库产品,关联【库存信息】聚合表
- 数值:命名为库存数,由「出库产品」填充
- 数值:命名为出库数量
- 单行文本:命名为出库产品名称,由「出库产品」填充
创建【库存信息】聚合表
选择数据源【入库表】、【出库表】两张表单,并配置「关联关系」为出库清单中的产品名称、入库清单中的产品名称字段。

配置「列标题」,字段为产品名称:

配置「指标」:

{"text":"入库表.入库清单.入库数量-出库表.出库清单.出库数量","marks":[{"from":{"line":0,"ch":0,"sticky":null},"to":{"line":0,"ch":15,"sticky":null},"value":"FORM-83AF6369978940489D2F200B142962E3F86O/numberField_m46f54st","invalid":false},{"from":{"line":0,"ch":16,"sticky":null},"to":{"line":0,"ch":31,"sticky":null},"value":"FORM-7FF4B505BED745A3BEA085064AE2DBA58F5U/numberField_m46f54st","invalid":false}],"isCmData":true}
配置「提交校验」:

{"text":"库存数>=0","marks":[{"from":{"line":0,"ch":0,"sticky":null},"to":{"line":0,"ch":5,"sticky":null},"value":"numberField_m46fa3rc","invalid":false}],"isCmData":true}
保存发布聚合表

在线试玩
- 注意:示例启用后,请按照下述步骤,重新发布聚合表方可使用。
