/water-dispatch 右侧路线卡的“线路优化”:计算并比较当前完整路线;所有任务尚未出库时可确认应用站序。没有真实路线或包含已出库/结束任务时只预览。service/routing/RouteStrategy.php 定义评分接口,RouteOptimizer 注入以下具体实现:
| 策略 | 目标与平局处理 |
|---|---|
| ShortestDistanceStrategy | 总距离、总完成用时、超时站数、超时秒数依次最小 |
| FastestArrivalStrategy | 总完成用时、距离、超时站数、超时秒数依次最小 |
| DeadlinePriorityStrategy | 超时站数、总超时秒数、总完成用时、距离依次最小 |
固定共同起点、既定批次成员、不返回仓库;最多8站穷举全部站序,求给定有向道路矩阵下的最优值。该结论不等于跨车辆、跨批次的全局最优,也不预测未来路况。超过8站明确要求拆批,不遗漏站点或悄悄退回直线。
总用时包含每站配送停留(0至120分钟);时限按预计完成配送时间计算,早到可直接配送,无最早服务时间窗。没有时限的站点不计超时;全部无时限时,时限策略等价于最快完成。
dispatch/board 与 dispatch/route 接口,取得站序、起点、目的地、送达时限。collectWaterRoadMatrix 调用高德JS API:最短距离使用驾车策略2,其余策略0;逐对查询起点到各站、各站之间的有向道路成本。同位置为零成本但保留各个配送任务;无道路连接为null,网络/配额错误中止并提示。POST /core/water/dispatch,action=optimize:传入 task_ids/points/matrix/strategy/departure_at/service_minutes。后端从Eloquent模型重新读取任务,校验坐标、共同起点、片区、矩阵格式和上限,再执行策略。action=optimize_apply 携带 route_id/token 修改现有路线;合单通过原 plan_commit 的各组 optimization_token 引用预览。预览绑定操作员及任务状态/坐标/时限/站序指纹;过期、跨用户、漏站或任务变化均拒绝。路线表 optimization 保存策略与当次估计,页面刷新后继续显示。底图用保存的策略重新查询道路,所以实时用时可能与保存时不同;地图用时不含配送停留,优化结果包含停留,页面已区分。
供水控制器、WaterBusiness、WaterDispatch、WaterLedger、WaterRoutePlanning及设备报告服务均通过 model/water 的Eloquent模型读写数据,不再使用Think ORM或直接 Db::table 查询业务表。模型包含配送、企业、商品、权益账户、路线、配送员、排班、订单、流水、套餐、代理、设备、内容及短期预览;配送/路线/账户定义模型关系。权限入口通过只读用途的WaterOperator/WaterOperatorRole模型读取原系统表。
WaterModel继承 support\Model,其底层为Illuminate Eloquent;固定模型白名单代替动态表名,统一搜索及分页口径。关闭自动时间戳,保留业务服务原 created_at/updated_at 更新规则。全部供水写入与事务使用同一Eloquent连接;测试和依赖业务服务的种子脚本也已迁移,防止两个ORM连接之间事务失效。框架原登录、菜单和其他业务模块仍保留既有Think实现。
php scripts/migrate_water_routing.php --apply,新增可空 sa_water_route.optimization 和 sa_water_route_preview,不删除旧表、任务或账本。回退应用时保留元数据表列。php -d extension=mbstring tests/water_routing_test.php;Windows用 scripts/start_water.ps1 启动,脚本按需通过进程级 PHP_INI_SCAN_DIR 加载 config/php/mbstring.ini,子进程继承,不修改全局php.ini。已有服务须先停止,避免重复监听。scripts/test-water-driving.mjs 覆盖有向道路矩阵、策略参数、取消、配额失败、不可达及分段不漏站。