feat(ticket): 添加水票订单配送流程功能
- 在GltTicketOrder实体类中新增配送相关的字段,包括配送状态、配送时间、收货人信息等 - 实现配送员端订单查询接口,支持按配送状态筛选和权限隔离 - 添加配送流程核心接口:接单、开始配送、确认送达、用户确认收货等功能 - 实现配送状态流转的状态机校验和并发安全的原子更新操作 - 优化数据库查询SQL,增加配送状态和租户ID的索引提升查询性能 - 添加配送员身份验证和权限检查机制,确保操作安全性
This commit is contained in:
14
docs/sql/2026-02-06_glt_ticket_order_delivery_fields.sql
Normal file
14
docs/sql/2026-02-06_glt_ticket_order_delivery_fields.sql
Normal file
@@ -0,0 +1,14 @@
|
||||
-- 水票配送订单:配送流程字段(需在数据库执行)
|
||||
-- 表:glt_ticket_order
|
||||
|
||||
ALTER TABLE glt_ticket_order
|
||||
ADD COLUMN delivery_status INT NULL DEFAULT 10 COMMENT '配送状态:10待配送、20配送中、30待客户确认、40已完成',
|
||||
ADD COLUMN send_start_time DATETIME NULL COMMENT '开始配送时间',
|
||||
ADD COLUMN send_end_time DATETIME NULL COMMENT '确认送达时间',
|
||||
ADD COLUMN send_end_img VARCHAR(512) NULL COMMENT '送达拍照留档图片URL',
|
||||
ADD COLUMN receive_confirm_time DATETIME NULL COMMENT '客户确认收货时间',
|
||||
ADD COLUMN receive_confirm_type INT NULL COMMENT '确认方式:10手动、20照片、30超时';
|
||||
|
||||
CREATE INDEX idx_glt_ticket_order_rider_status ON glt_ticket_order (tenant_id, rider_id, delivery_status, deleted);
|
||||
CREATE INDEX idx_glt_ticket_order_user_status ON glt_ticket_order (tenant_id, user_id, delivery_status, deleted);
|
||||
|
||||
98
docs/水票配送订单-后端提示词.md
Normal file
98
docs/水票配送订单-后端提示词.md
Normal file
@@ -0,0 +1,98 @@
|
||||
# 水票配送订单:后端提示词(可直接发给后端)
|
||||
|
||||
> 目标:把“水票下单后 -> 配送员接单/配送 -> 用户确认 -> 自动确认”的闭环放到后端,用明确的字段 + 状态机校验保证不越权、不乱跳状态、并发不重复接单。
|
||||
>
|
||||
> 接口前缀:当前后端控制器为 `@RequestMapping("/api/glt/glt-ticket-order")`,下文默认都带 `/api` 前缀(如需兼容旧路径,可做网关转发或保留旧路由)。
|
||||
|
||||
## 0) 角色与权限边界(务必在后端兜底)
|
||||
- 用户端(小程序用户):只能看/操作自己的订单(`userId` = token userId)。
|
||||
- 配送员端:只能看/操作分配给自己的订单(`riderId` = token userId / rider userId)。
|
||||
- 管理端:按后台权限控制(可查询/派单/改状态,但仍需 tenantId 隔离)。
|
||||
|
||||
建议:对“配送员端接口”忽略前端传入的 `riderId/userId/tenantId`,统一从登录态注入,避免越权。
|
||||
|
||||
## 1) 订单查询(配送员端)
|
||||
建议提供配送员专用分页接口:`GET /api/glt/glt-ticket-order/rider/page`(避免与后台管理分页混用)。
|
||||
请支持以下筛选,并保证权限隔离:
|
||||
- `deliveryStatus`:10待配送、20配送中、30待客户确认、40已完成(配送员端必要;不传默认=10)
|
||||
- `keywords`:支持按地址/备注等模糊搜索(可选)
|
||||
- 排序:建议默认 `sendTime asc, createTime desc`(或沿用后端默认排序,但请告知前端)
|
||||
|
||||
权限隔离要求(配送员端):
|
||||
- 只返回当前登录配送员的订单:后端强制 `param.riderId = loginUserId`(前端传不传都一样)。
|
||||
- `tenantId/deleted` 等同样后端兜底(只查当前租户、只查未删除)。
|
||||
|
||||
返回字段建议(配送员端用得上):
|
||||
- 门店/仓库/用户/配送员的展示字段:`storeName/storeAddress/storePhone`、`warehouseName/warehouseAddress`、`nickname/phone/avatar`、`riderName/riderPhone`(现有 `pageRel/listRel` 已在做关联返回)。
|
||||
- 导航相关(详见第 5 节):收货地址 `lat/lng`、门店/仓库 `lngAndLat`(可关联返回或做快照字段)。
|
||||
|
||||
## 2) 配送流程字段(建议后端落库并回传)
|
||||
订单表建议确保有以下字段(当前前端已按这些字段做流程判断/展示):
|
||||
- `riderId/riderName/riderPhone`:配送员信息
|
||||
- `deliveryStatus`:10/20/30/40
|
||||
- `sendStartTime`:配送员点击“开始配送”的时间(建议 datetime)
|
||||
- `sendEndTime`:配送员点击“确认送达”的时间(建议 datetime)
|
||||
- `sendEndImg`:送达拍照留档图片 URL(可选/必填由后端策略决定;建议 varchar(512))
|
||||
- `receiveConfirmTime`:客户确认收货时间(建议 datetime)
|
||||
- `receiveConfirmType`:10客户手动确认、20配送照片自动确认、30超时自动确认
|
||||
|
||||
数据库变更(示例SQL见:`docs/sql/2026-02-06_glt_ticket_order_delivery_fields.sql`)。
|
||||
|
||||
强烈建议把“配送状态”与“业务状态(status=0/1、deleted=0/1)”分开,避免混用:
|
||||
- `status/deleted`:系统通用字段(现有逻辑)
|
||||
- `deliveryStatus`:配送流程状态(本需求新增)
|
||||
|
||||
## 3) 状态流转与校验(强烈建议在后端做)
|
||||
请在更新订单时做状态机校验,避免前端绕过流程:
|
||||
- `10 -> 20`:仅允许订单属于当前配送员,且未开始/未送达
|
||||
- `20 -> 30`:配送员确认送达(可带 `sendEndImg`)
|
||||
- `20/30 -> 40`:完成;来源可能是
|
||||
- 客户手动确认(写 `receiveConfirmTime` + `receiveConfirmType=10`)
|
||||
- 配送照片直接完成(写 `receiveConfirmTime` + `receiveConfirmType=20`,并要求 `sendEndImg`)
|
||||
- 超时自动确认(写 `receiveConfirmTime` + `receiveConfirmType=30`,建议由定时任务执行)
|
||||
|
||||
并发/幂等建议(避免重复点击/重复请求带来的脏数据):
|
||||
- 所有“状态变更接口”用条件更新实现原子校验:`UPDATE ... SET ... WHERE id=? AND rider_id=? AND delivery_status=? AND deleted=0`
|
||||
- 对重复调用做幂等:
|
||||
- `start`:如果已是 20 则直接返回成功;如果已到 30/40 返回“状态不允许”
|
||||
- `delivered`:如果已是 30/40 则返回成功(或提示已送达);避免重复写 `sendEndTime`
|
||||
- `confirm-receive`:如果已是 40 则返回成功(或提示已完成)
|
||||
|
||||
## 4) 建议新增/明确的接口能力
|
||||
为了避免并发抢单/越权更新,建议新增更语义化的接口(或在 update 内做等价校验):
|
||||
- 接单(抢单/派单):`POST /api/glt/glt-ticket-order/{id}/accept`
|
||||
- 配送员端:后端原子校验:仅当 `rider_id IS NULL`(或为 0)时才能写入当前 rider 信息
|
||||
- 管理端派单:允许传 `riderId`,但需校验骑手归属门店/租户(如有该约束)
|
||||
- 开始配送:`POST /api/glt/glt-ticket-order/{id}/start`
|
||||
- 写:`sendStartTime=now`、`deliveryStatus=20`
|
||||
- 校验:必须 `riderId=当前登录配送员` 且当前 `deliveryStatus=10`
|
||||
- 确认送达:`POST /api/glt/glt-ticket-order/{id}/delivered`
|
||||
- 入参:`sendEndImg`(可选/必填,按策略)
|
||||
- 写:`sendEndTime=now`、`deliveryStatus=30`、`sendEndImg`
|
||||
- 可选策略 A(推荐可配置):若 `sendEndImg` 必填且存在,则可直接 `deliveryStatus=40` 并写 `receiveConfirmTime/Type=20`
|
||||
- 客户确认收货:`POST /api/glt/glt-ticket-order/{id}/confirm-receive`
|
||||
- 校验:只能本人 `userId` 操作,且必须 `deliveryStatus=30`
|
||||
- 写:`deliveryStatus=40`、`receiveConfirmTime=now`、`receiveConfirmType=10`
|
||||
|
||||
接口返回建议:
|
||||
- 成功统一返回 `ApiResult.success(...)`
|
||||
- 失败请返回明确 msg(例如:`无权限`、`订单不存在`、`订单状态不允许`、`订单已被其他配送员接单`)
|
||||
|
||||
## 5) 为了“导航到收货地址/取货点”的字段补充(建议)
|
||||
当前仅有 `address` 字符串,无法在小程序内 `openLocation` 精准导航;建议补充:
|
||||
- 收货地址(推荐至少返回):`receiverName`、`receiverPhone`、`province/city/region/address/fullAddress`、`lat/lng`
|
||||
- 取货点(门店/仓库,推荐至少返回):`store.lngAndLat`、`warehouse.lngAndLat`
|
||||
|
||||
实现方式二选一:
|
||||
- 方式 A(更快):查询时关联 `shop_user_address`、`shop_store`、`shop_warehouse`,把经纬度字段透出给前端。
|
||||
- 方式 B(更稳):下单时把收货地址的 `name/phone/lat/lng/fullAddress` 以及门店/仓库 `lngAndLat` 做快照写入订单,避免后续数据变更影响历史订单导航。
|
||||
|
||||
## 6)(可选但很有用)超时自动确认规则
|
||||
- 建议后端提供可配置项:`autoConfirmHours`(例如 24h/48h)
|
||||
- 定时任务扫描:`deliveryStatus=30` 且 `sendEndTime < now - autoConfirmHours` 的订单
|
||||
- 原子更新:只更新仍处于 30 的订单,写入 `deliveryStatus=40`、`receiveConfirmTime=now`、`receiveConfirmType=30`
|
||||
|
||||
## 7)(可选)字段/枚举建议(便于前后端对齐)
|
||||
- `deliveryStatus`:10待配送、20配送中、30待客户确认、40已完成
|
||||
- `receiveConfirmType`:10客户手动确认、20配送照片自动确认、30超时自动确认
|
||||
- 时间字段统一返回格式:`yyyy-MM-dd HH:mm:ss`(与项目现有 `@JsonFormat` 风格一致)
|
||||
Reference in New Issue
Block a user