从零开发家政派单小程序系统,架构设计与派单算法实战解析
家政派单小程序系统的开发,本质上是将“服务供给(师傅)—需求匹配(用户)—交易履约(订单)”这条链路线上化、智能化。很多团队在立项初期容易陷入功能堆砌的误区,直接照着竞品画原型,而忽略了核心的两件事:系统架构能否支撑多端协同、派单逻辑能否平衡用户体验与师傅效率。本文结合同城上门服务类项目的通用技术方案,从架构分层、数据库设计、派单算法三个维度展开,给出可直接落地的实战思路。
一、系统架构设计:多端协同的模块化拆分
家政派单系统通常涉及用户端(小程序/H5/App)、师傅端(接单App/小程序)、管理后台(PC Web)三个核心入口。参考目前主流的开源家政解决方案,技术栈一般选用Spring Boot + MyBatis Plus + MySQL + Redis作为后端底座,前端用户端与师傅端采用UniApp(Vue语法)实现一套代码多端编译,管理后台则使用Vue + Element UI。
在工程结构上,建议按业务域拆分为以下模块:
| 模块 | 职责范围 | 关键依赖 |
|---|---|---|
gateway | 统一认证、限流、路由 | Spring Cloud Gateway / Sa-Token |
user-service | 用户注册登录、地址管理、会员体系 | Redis(验证码)、JWT |
order-service | 订单创建、状态流转、取消/退款 | RabbitMQ(延迟队列)、状态机 |
dispatch-service | 派单策略、师傅评分、抢单池管理 | Redis(ZSet)、GeoHash |
|pay-service| 支付/退款、对账单 | 支付V3 SDK |
|im-service| 在线聊天、消息推送 | WebSocket、Netty |
|admin-service| 商户入驻、师傅审核、佣金配置 | 工作流引擎(可自制) |
一个容易忽略的细节是:必须将“派单”独立成服务。很多快速原型项目把派单逻辑塞进订单服务里,初期能跑,但一旦增加“多商户独立派单”“师傅技能标签匹配”等需求,改动会像滚雪球一样膨胀。独立出来之后,无论是后续引入算法升级还是人工调度干预,都只需要替换dispatch-se rvice内部实现。
二、核心数据模型与订单状态机
2.1 订单主表设计
家政订单不同于普通电商订单,它包含“服务时间、服务地址、服务项目、期望师傅性别/年龄、上门费用”等动态字段。建议采用主表 + 扩展表的方式:
CREATETABLE`dispatch_order`(`id`BIGINTPRIMARYKEYAUTO_INCREMENT,`order_no`VARCHAR(32)NOTNULLCOMMENT'业务单号',`user_id`BIGINTNOTNULL,`merchant_id`BIGINTDEFAULTNULLCOMMENT'商户ID,平台自营为空',`service_items`JSONNOTNULLCOMMENT'服务项及数量 [{item_id, qty}]',`address`VARCHAR(255)NOTNULL,`lng`DECIMAL(10,7)NOTNULL,`lat`DECIMAL(10,7)NOTNULL,`expect_start_time`DATETIMENOTNULL,`expect_end _time`DATETIMENOTNULL,`budget_amount`DECIMAL(10,2)DEFAULTNULLCOMMENT'悬赏模式预算',`status`TINYINTNOTNULLCOMMENT'见状态机',`created_at`DATETIMEDEFAULTCURRENT_TIMESTAMP,KEY`idx_status_time`(`status`,`expect_start_time`),KEY`idx_merchant`(`merchant_id`))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;2.2 订单状态机定义
派单系统的复杂之处在于状态流转的“异常分支非常多”。比如:师傅已接单但用户取消、师傅到达后发现需加项、悬赏单超时未有人接单。推荐画出完整状态图后再编码,核心状态如下:
PENDING_PAY → WAIT_DISPATCH(已支付待派单) WAIT_DISPATCH → DISPATCHING(正在指派中) DISPATCHING → ACCEPTED(师傅已接单) DISPATCHING → TIMEOUT_CLOSED( 超时未接,自动关闭或转人工) ACCEPTED → WORKING(师傅开始服务) WORKING → WAIT_COMMENT(等待用户评价) WAIT_COMMENT → COMPLETED(完成) ACCEPTED → USER_CANCEL / WORKER_CANCEL → REFUNDING → REFUNDED在代码实现中,不要用if/else散落判断状态,建议使用状态模式 + 事件驱动。结合 Spring StateMachine 或自研状态机(一个枚举 + 一个 Map 表驱动转移即可),既避免非法流转,又
方便后续增加“超时自动取消”等定时任务。
三、派单算法实战:从抢单到智能指派
3.1 三种业务模式的派单差异
- 一口价:先到先得 + 权重排序。师傅端刷新“可抢单池”,但系统不按纯先来后到显示,而是按距离、评分、繁忙程度综合排序展示。
- 悬赏模式:类似一口价,但预算可上浮,系统优先推送给“高完单率”的师傅,并允许师傅“提价接单”或“降价抢单”。
3.2 核心评分算法:LBS + 多因子加权
自动派单的核心思路是为每位在线师傅计算“综合匹配分”,选分派单。公式如下:
score = w1 * s ervice_match + w2 * distance_score + w3 * worker_rating - w4 * current_load其中:
service_match:师傅的服务技能标签与订单服务项目是否匹配,完全匹配=100分,部分匹配按比例得分。distance_score:师傅当前位置与订单地点的距离评分,可采用分段线性函数,3公里内满分,10公里以上衰减到0。worker_rating:师傅历史评分(5分制换算成100分)。current_load:师傅当前未完成订单数,作为惩
罚项。
落地时,可利用 Redis GeoHash 快速筛选出订单地点周围5公里的师傅,再加载其标签和评分做精细计算:
publicLongdispatch(OrderDOorder){// 1. GeoHash 粗筛:中心点 5kmList<Long>candidateIds=geoService.nearbyWorkerIds(order.getLng(),order.getLat(),5*1000);// 2. 加载师傅详情(技能、评分、负载)List<Worker>workers=workerMapper.selectBatchIds(candidateIds);// 3. 多因子打分returnworkers.stream().filter(w->w.getStatus()==WorkerStatus.ONLINE).filter(w->skillMatch(w,order.getServiceItems())>0).max(Comparator.comparingDouble(w->computeScore(w,order))).map(Worker::getId).orElse(null);// 无合适人选,进入人工派单池}3.3 防“恶意抢单”与超时兜底
真实场景中,师傅端抢单会存在外挂点击、无线程安全问题。建议后端做两层防护:
- 抢单令牌:用户下单支付后,生成一个
dispatch_token(有效期内有效),师傅点击抢单时必须携带该 token,且 token 的订单号 + 师傅 ID 使用 RedisSETNX锁定
,防止并发重复抢单。 - 超时重派机制:若自动派单后师傅 30 秒未确认,则订单自动释放回抢单池,并降低该师傅的调度优先级。若有紧急订单,可引入“逐级扩大搜索半径”的策略——先 3km,再 5km,后全城广播。
四、多商户与员工管理的关键设计
如果系统支持多商户入驻(如多个家政公司入驻平台,各自管理自己的师傅),派单范围就不仅要考虑地理距离,还要考虑商户服务区域。实际项目中的做法是:商户后台配置“服务商圈”(圆形区域或多边形区域),派单时层过滤是“订单位置落在哪些商户的商圈内”,第二层才是商户下的师傅筛选。
另外,部分家政公
司内部存在“员工制”师傅(底薪+提成)和“众包师傅”(纯派单)两种角色。员工制的师傅订单分配应遵循“系统强制指派”模式,众包则采用“抢单模式”。这可以通过师傅表上的dispatch_mode字段区分,而不是为两种角色建立两套订单流。
技术实现上,员工订单同样走自动派单逻辑,但score计算时给员工制师傅加一个“优先系数”(例如 1.2),保证其先于众包师傅看到订单。
五、性能优化与FAQ
5.1 性能优化要点
- 抢单池使用 Redis 而不是 MySQL 轮询。将待抢订单的简要信息缓存到 Redis Has
h 中,师傅端通过长轮询或 WebSocket 实时获取可抢单列表,避免频繁打到数据库。 - 订单状态变更必须走幂等设计。每次状态流转带上“前一状态”条件更新,例如
UPDATE dispatch_order SET status = 5 WHERE id = 1001 AND status = 4,返回影响行数为 0 说明并发冲突。 - 师傅实时轨迹无需写入业务 DB。使用 Redis GEO 存储师傅位置,定期(每5秒)上报,过期自动清除。
5.2 常见问题FAQ
Q:家政派单小程序系统开发需要具备哪些技术栈?
后端建议 Spring Boot + MyBatis Plus + MySQL + Redis,前端使用 UniApp(Vue语法)以支持小程序、公众号、H5 多端复用。管理后台可采用 Vue + Element UI。消息推送可集成订阅消息或极光推送。
Q:自动派单和抢单模式如何取舍?
如果你运营的是自营团队且订单密度高,全自动派单效率更好;如果走平台撮合模式,抢单制能让师傅自主决定接单节奏,提升留存。实践是两种模式共存,并允许订单发布方指定“仅抢单”或“系统派单”。
Q:开发一个完整系统需要从哪些模块开始做?
建议按“用户端下单
→ 支付 → 派单 → 接单 → 服务 → 评价”这条主链路先跑通,再逐步补充商户入驻、员工管理、分销推广、优惠券等辅助业务。先把订单和派单这两个核心闭环做稳定,远好过一开始就铺十几个模块。
Q:如何保证派单算法的公平性?
不要让某个师傅长期获得高评分而垄断订单。可以在评分公式中加入“近 N 小时接单量”作为惩罚项,并把“拒单率”纳入算分——多次拒单的师傅权重下调。同时,在后台提供给运营人员“手动改派”的权限,用于处理算法不合理的极端情况。
