日期:2026-08-26
我们接手一个多校区驾校的约车系统改造。原来学员约车全靠打电话和在微信群里喊,教练排班是一张 Excel 表,经常出现同一辆车同一个时段被两个人约走,也有车整个上午空着没人约。教练的工时靠手工统计,月底算提成能对到吵架。学员那边体验更差,想练车得提前好几天抢,临时有事去不了也没人通知教练,白等是常态。我们进场第一周就翻了预约记录,时段冲突的订单占了将近一成,空置时段也接近两成,两头浪费,教练和学员都不满意。驾校校长最头疼的是投诉,约车撞车这种事只要发生一次,学员转头就去隔壁驾校了,所以这事拖不得。更麻烦的是寒暑假旺季,学员集中约车,系统完全靠人肉协调,校长说那两个月他手机不敢关,半夜还有人问能不能加场,管理成本极高,校长自己都成了客服。
我们做了在线约车加智能排班。学员端能按校区、车型、时段选车约练,系统实时显示哪些时段还有空位;教练端能看到自己当天的排班和车辆,跨校区通勤时间也一并算进去。后台把每辆车和每个教练做约束绑定,一辆车同一时段只能被约一次,冲突在提交时就拦下,不会等到现场才发现车被占用。教练工时按实际约课记录自动累加,月底提成直接出报表,不用再手工对数。我们还加了缺练预警,某个学员超过两周没约车,系统会提醒教练主动联系,把流失拦在前面。驾校把这套接到了财务,约课记录和课时费打通,教练拿手机就能看自己这个月跑了多少课时、该拿多少,争议少了一大半。此外,练车日志也接进了系统,每次练车自动记录车型、时长、教练,学员结业时能拉出完整练车档案,校长用来做通过率分析,哪类学员练得少挂得多的,提前补练,教学端也有了数据抓手。
约车冲突校验是第一道关。我们一开始用数据库唯一索引拦重复,但高并发下两个请求同时进,唯一索引报错才回滚,体验很差。后来改成先查可用时段缓存,提交时带版本号做乐观锁,冲突在应用层就挡掉,几乎不再撞车。教练车辆约束比想象中麻烦,跨校区通勤时间如果不算,排班就会把同一个教练上午排 A 校区、半小时后排 B 校区,人根本赶不过去。我们给每个教练加了通勤矩阵,排班时强制留出转场时间,这一步踩过坑,第一版没加,结果有教练被排了跨城连场,当场撂挑子,后来通勤约束成了必选项。工时核算要和约课记录强一致,我们用了事件溯源,每次约车、取消、改期都落一条事件,月底按事件重算,提成再也不会对不上。缺练预警用滑动窗口统计学员最近约车间隔,超过阈值就触发,但阈值定太短会误伤偶尔忙的学员,我们调到两周才稳定。缓存的一致性也踩过坑,时段缓存和数据库偶尔不同步,出现过缓存显示有空位实际已约满,后来加了写后失效和定时校准,才彻底没有超约,这一课是拿一次现场纠纷换来的。
案例片段(已脱敏): 约车冲突校验与排班约束配置(示意): booking.lock: optimistic_version vehicle.slot_unique: per_car_per_slot coach.transit_matrix: enabled coach.min_transit_min: 45 cache.invalidate_on_write: true 某驾校上线后约车冲突率从约 9% 降到近乎为 0,车辆空置率从约 18% 降到 7%,教练工时统计从三天压到实时,旺季校长手机终于敢关了。
我们主要盯约车冲突率、车辆空置率、教练工时利用率和学员等待时长。冲突率基本归零,学员再也不用担心到了现场车被别人占了;空置率砍掉六成,原来空着的车现在能被约满,驾校等于多出不少产能。教练工时利用率上去之后,收入透明度高了,离职率也小了点,校长说最明显的是月底不用再和教练对账到半夜。学员等待时长从平均三四天压到当天或次日就能约上,约课爽了,续费率和转介绍都跟着涨。文中数据为项目复盘口径,已做脱敏,实际值随校区规模波动。校长后来把缺练预警的名单直接推给招生,哪个学员快流失了提前介入,留存比单纯发优惠券有用得多。我们还把练车档案的通过率分析接到了教学改进,挂科率高的练习项系统自动建议加练,整体通过率也跟着提了一点点,校长这才觉得系统不只是管约车,还帮到了教学。
约车这类资源预约,冲突校验一定要做在应用层而不是等数据库报错,乐观锁比唯一索引体验好太多,学员提交那一刻就知道行不行,不会白跑。教练和车辆的约束是排班系统的命门,通勤时间、休息时间这些隐性约束漏一个就会出乱子,我们就是没算通勤吃过一次亏,排班算法再聪明也架不住人赶不过去。工时核算别手工对数,事件溯源把每次变动都记下来,月底重算永远对得上,谁也赖不掉。缓存和数据库的一致性别想当然,时段缓存写后失效这一条我们交过超约的学费,后来才踏实。我现在的看法是,这类系统最值钱的反而不是约车界面,而是背后的约束引擎,把人、车、时间这三者的关系理清楚,排班自然就顺了,剩下的都是前端功夫。