预约功能难点
在实现云开发微搭低代码的「美业行业模版」时,经常会对在工作日预约周末的某项服务,并且制定特定的技师。在预约的时候,可能会发生重复预约。
什么是重复预约呢? 例如:预约A中,预约了员工A在 2021/10/01 的 9:00 -10:00;预约B中,预约了员工B在 2021/10/01 的 8:00 - 12:00 ;两个预约在时间段上有重叠。
预约难点体现在:
- 为了防止重复预约,在下单预约的时候,应该进行检测
- 控制检查预约时间、新建预约、删除预约、修改预约的时间复杂度
解决方案
新增员工工作时间表(employer_work_time),字段如下:
1 | _id: string; |
关于员工工作时间表(employer_work_time)的time字段的设计:
- 每天时间按照30分钟进行切分,一天可以切分为48份。
- 使用BitMap,用无符号二进制表示,需要48位,初始状态每位都是0。共需要6byte,mysql中一个bigint type即可,flexdb中使用number即可。
- 二进制运算时间复杂度O(1)
原预约记录表新增字段:
1 | // 关联员工工作时间表记录的_id,能查到提供服务的员工,以及提供服务的日期 |
整体流程
存储格式
如果用户A预约的时候,预约了员工A的 0:00 - 1:00 ,那么二进制为:11000…000(共46个0),存储的字段值就是:211106232532992 。
另一个用户B在进行预约的时候,假设也选中了员工A,接口查询到员工A在10-01这天的数据有记录,并且time为211106232532992。将time字段转成二进制数组,即:[1, 1, 0, 0, … , 0]。
前端拿到此数组后,可以将为1的时间段禁用。用户B预约时,无法选中员工A的0:00~1:00时间段,从而达到防止重复预约的目的。
新增预约
- 用户创建预约:假设用户B选中了1:00 - 1:30,前端传给后端的time字段就是:[0, 0, 1, 0, 0, …],处理成二进制之后是:0010…0(45个0)。然后进行校验、数据更新、以及失败返回:
- 数据校验:前端传入的二进制与数据表中记录的字段进行 & 操作(
0010...0 & 11000...00 = 00....0000
),如果结果是0,那么就说明合法,没有重复字段,进行数据更新;如果结果不为0,那么就说明有重复字段,接口失败返回。 - 数据更新:
- 更新员工工作时间表的time字段。time字段的新值为前端传入的二进制和数据表中记录的字段的 | 操作的结果。这里就是
010...0 | 11000...00 = 1110....000
,代表 0:00 - 1:30 这个时间段都有预约了。 - 更新预约记录表的service_time字段。值为前端传入的二进制,即:0010…0
- 更新员工工作时间表的time字段。time字段的新值为前端传入的二进制和数据表中记录的字段的 | 操作的结果。这里就是
- 数据校验:前端传入的二进制与数据表中记录的字段进行 & 操作(
取消预约
- 用户取消预约:假设用户B取消预约。取出预约记录表的service_time字段,根据employer_work_time_id反查员工工作时间表记录,更新其上的time字段。
运算使用异或操作即可:0010...0 ^ 1110....000 = 110...0
更新预约
- 用户更新时间:操作上也是二进制,相当于先取消,再创建预约。借助「事务」保证原子性即可。