资讯动态

上门做饭小程序搭建:档期管理与订单流转方案

发布时间:2026/9/30 5:28:54 来源:尧图企业网站定制
上门做饭小程序搭建档期管理与订单流转方案上门做饭小程序属于同城本地履约类系统和普通电商最大差异在于服务依赖厨师的时间资源。用户下单本质是预约厨师特定时间段的服务而不是实物商品。很多项目开发时直接套用电商订单逻辑忽略档期资源锁定容易出现同一时段厨师被多次下单、订单状态错乱、取消订单后档期无法释放等问题造成大量客诉。本文基于SpringBoot搭建小程序后端围绕档期资源模型、订单状态机、全链路流转逻辑展开附带Java核心代码和数据库设计给出一套可落地的实现方案。一、业务场景与开发痛点1.1 业务场景概述整套小程序分为用户端、厨师端、平台管理端。用户端浏览厨师信息、查看厨师可预约档期、选择预约日期和时段、填写地址与菜品需求、提交订单支付、查看订单进度、服务完成后评价。厨师端设置可接单日期与时段、查看预约订单、接单确认、上门履约、完成服务。平台端管理厨师账号、查看档期占用情况、监控订单流转、处理售后异常。核心业务链路厨师维护档期 → 用户查询可用时段 → 锁定档期创建订单 → 用户支付 → 厨师接单履约 → 服务完成/订单取消档期资源释放。1.2 常见开发痛点档期模型设计粗糙仅记录日期没有拆分时段无法支持午市、晚市分开预约容易出现时间冲突。并发预约场景缺少资源锁高并发下同一厨师同一时段生成多笔订单造成超约。订单状态缺少状态机约束代码中随意修改状态出现已取消订单仍然标记档期占用的脏数据。订单取消、支付超时后档期资源没有自动释放厨师时段长期被占用无法继续接单。档期和订单数据不同步厨师修改可接单时间已经预约的历史订单没有做保护引发履约纠纷。二、整体技术架构设计2.1 技术栈选型后端采用Java SpringBoot MyBatis Plus数据库MySQL8.0Redis用于档期资源锁与缓存可用档期配合定时任务处理超时订单。核心能力厨师档期维护、时段资源锁定、订单状态机流转、超时订单自动处理、档期资源回收。2.2 档期模型设计上门做饭服务不能简单按天管理需要拆分为日期时段组合作为最小资源单元。时段示例午市(10:00-14:00)、晚市(16:00-21:00)。厨师可以自主设置每周哪些时段可接单也可以单独屏蔽某一天。当用户预约成功后该【厨师ID日期时段】资源标记为占用直到订单完成或取消后释放。2.3 订单状态机设计订单状态流转严格限制禁止随意跳转待支付用户提交预约档期临时锁定限时15分钟完成支付超时自动取消并释放档期。待接单用户支付成功等待厨师确认接单。服务中厨师确认接单上门服务进行阶段。已完成服务结束订单正常闭环。已取消用户主动取消 / 支付超时取消档期资源释放。已退款履约前或履约中发起退款退款完成档期释放。合法流转规则待支付可以流转到待接单、已取消待接单可以流转到服务中、已退款服务中可以流转到已完成、已退款已完成、已取消、已退款为终态不可变更。三、核心模块设计3.1 档期管理模块档期分为两层厨师基础可接单模板、当日档期占用记录。基础模板厨师设置每周几、哪些时段可以接单作为默认规则。当日档期系统根据基础模板生成每日可用档期用户预约后生成占用记录。厨师可以手动关闭某一天某个时段临时暂停接单。查询逻辑用户查询厨师档期时优先读取Redis缓存返回可用时段减少数据库压力。3.2 订单流转模块预约下单校验档期是否可用通过Redis分布式锁锁定时段资源生成待支付订单。支付回调支付成功后变更订单状态为待接单推送消息通知厨师。厨师接单确认接单订单流转为服务中。履约完成厨师标记服务完成订单变为已完成。取消/超时触发档期释放逻辑解除资源占用。四、Java核心代码实现4.1 订单状态枚举状态机/** * 上门做饭小程序订单状态枚举 */ public enum CookOrderStatusEnum { WAIT_PAY(1, 待支付), WAIT_ACCEPT(2, 待接单), SERVING(3, 服务中), FINISHED(4, 已完成), CANCEL(5, 已取消), REFUND(6, 已退款); private final Integer code; private final String desc; CookOrderStatusEnum(Integer code, String desc) { this.code code; this.desc desc; } /** * 校验状态是否允许流转 */ public static boolean canTransfer(Integer oldStatus, Integer newStatus) { if (oldStatus.equals(WAIT_PAY.getCode())) { return newStatus.equals(WAIT_ACCEPT.getCode()) || newStatus.equals(CANCEL.getCode()); } if (oldStatus.equals(WAIT_ACCEPT.getCode())) { return newStatus.equals(SERVING.getCode()) || newStatus.equals(REFUND.getCode()); } if (oldStatus.equals(SERVING.getCode())) { return newStatus.equals(FINISHED.getCode()) || newStatus.equals(REFUND.getCode()); } // 终态不能变更 return false; } public Integer getCode() { return code; } }4.2 档期锁定与释放服务Service Slf4j public class CookScheduleService { Autowired private RedisTemplateString, Object redisTemplate; private static final String SCHEDULE_LOCK_KEY cook:schedule:lock:%s:%s:%s; /** * 锁定厨师档期资源 * param cookId 厨师ID * param bookDate 预约日期 yyyy-MM-dd * param timeSlot 时段标识 * return 锁定结果 */ public ResultBoolean lockSchedule(Long cookId, String bookDate, String timeSlot) { String key String.format(SCHEDULE_LOCK_KEY, cookId, bookDate, timeSlot); // 锁定有效期24小时兜底防止死锁 Boolean success redisTemplate.opsForValue().setIfAbsent(key, locked, 24, TimeUnit.HOURS); if (!success) { return Result.error(该时段已被预约请更换日期或时段); } log.info(档期锁定成功 cookId:{},date:{},slot:{}, cookId, bookDate, timeSlot); return Result.success(true); } /** * 释放档期资源 */ public void unLockSchedule(Long cookId, String bookDate, String timeSlot) { String key String.format(SCHEDULE_LOCK_KEY, cookId, bookDate, timeSlot); redisTemplate.delete(key); log.info(档期资源释放 cookId:{},date:{},slot:{}, cookId, bookDate, timeSlot); } }4.3 超时订单定时任务自动取消释放档期Component EnableScheduling Slf4j public class OrderTimeoutTask { Autowired private CookOrderMapper orderMapper; Autowired private CookScheduleService scheduleService; /** * 每分钟扫描待支付超时订单 */ Scheduled(cron 0 * * * * ?) public void handleTimeoutOrder() { ListCookOrder timeoutOrders orderMapper.selectTimeoutWaitPayOrder(); if (CollectionUtils.isEmpty(timeoutOrders)) { return; } int count 0; for (CookOrder order : timeoutOrders) { // 状态机校验变更为已取消 if(!CookOrderStatusEnum.canTransfer(order.getStatus(), CookOrderStatusEnum.CANCEL.getCode())){ continue; } order.setStatus(CookOrderStatusEnum.CANCEL.getCode()); orderMapper.updateById(order); // 释放档期 scheduleService.unLockSchedule(order.getCookId(), order.getBookDate(), order.getTimeSlot()); count; } log.info(超时订单处理完成共取消{}笔订单, count); } }五、数据库表设计5.1 厨师档期配置表 cook_schedule_config核心字段id、cook_id、week_day、time_slot、is_enable、create_time作用存储厨师每周可接单时段模板。5.2 厨师档期占用表 cook_schedule_occupy核心字段id、cook_id、book_date、time_slot、order_id、status作用记录每日时段占用情况关联订单ID作为数据库层面的档期记录。5.3 预约订单表 cook_order核心字段id、order_no、user_id、cook_id、book_date、time_slot、address、total_price、status、pay_expire_time、create_time作用保存用户预约订单status绑定状态机pay_expire_time用于超时任务判断。六、开发优化与避坑缓存与数据库双校验Redis锁做并发拦截数据库作为最终一致性兜底防止缓存宕机导致超约。历史预约保护厨师修改档期模板不能修改已经存在有效订单的时段避免破坏已预约订单。状态变更统一收口所有订单状态修改必须调用状态机校验方法禁止直接update修改status字段。幂等设计支付回调、订单完成回调都要增加幂等key防止重复调用导致状态多次变更。消息通知联动订单状态变更后通过小程序消息推送用户和厨师及时同步预约、接单、取消信息。七、总结上门做饭小程序的核心难点不在于前端页面展示而是档期资源的管理和订单全流程状态流转。档期是厨师的核心服务资源使用【厨师日期时段】作为最小资源单元搭配Redis分布式锁解决并发预约冲突通过状态机约束订单流转保证订单与档期数据联动。订单一旦取消或者超时必须自动释放档期资源最大化厨师接单能力。该方案可以直接应用于上门做饭小程序后端开发还可以扩展菜品套餐管理、订单分佣、评价体系、节日溢价等功能适配同城私厨上门服务的商业化需求。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑