Jelajahi Sumber

明确闪送 App 订单列表与详情契约

骑手列表统一采用外卖订单的分页、页签和位置参数,用户列表移除多余筛选。
App 详情直接返回订单字段,去除 order、images、logs 包装,并明确接单前地址与敏感字段边界。
qmj 3 hari lalu
induk
melakukan
17888f8c86

+ 13 - 8
specs/024-flash-delivery/contracts/api.md

@@ -33,12 +33,14 @@
 | GET | `/system/flashDelivery/home` | 返回当前时间存在运价时段的服务及摘要 `serviceType,pricingId,startTime,endTime,startingDistance,startingFare,distance,freight,pricingVersion,currency`;不返回内部更新人、时间或地图密钥 |
 | POST | `/system/flashDelivery/quote` | `serviceType,packageType,packageSize,pickup,delivery` |
 | POST | `/system/flashDelivery/orders` | 报价请求字段 + `clientRequestId,deliveryMode,scheduledPickupStartAt?,scheduledPickupEndAt?,pinRequired?,senderImageUrls?,userNote?`;服务端重算并幂等创建 |
-| GET | `/system/flashDelivery/orders` | `pageNum,pageSize,status?,scene?,serviceType?`;`scene=matching/progress/done/cancelled`;仅本人 |
-| GET | `/system/flashDelivery/orders/{id}` | 本人完整详情、凭证和日志 |
+| GET | `/system/flashDelivery/orders` | `page,size`;仅本人,按创建时间倒序返回全部状态的用户列表摘要 |
+| GET | `/system/flashDelivery/orders/{id}` | 本人 App 订单详情;`data` 直接为订单字段,不返回原始状态日志 |
 | POST | `/system/flashDelivery/orders/{id}/cancel` | `{"reason":"行程变化"}`;仅待接/已接 |
 | POST | `/system/flashDelivery/orders/{id}/confirmReceipt` | 无 body;仅 DELIVERED |
 
-报价响应 data:`serviceType,pricingId,startTime,endTime,distanceMeters,distanceSource,estimatedDurationSeconds?,startingDistance,startingFare,distance,freight,billableDistance,distanceFee,amount,currency,pricingVersion`。`billableDistance` 为按外卖规则处理 0.5 公里边界后的计费公里数,`distanceFee` 与 `amount` 为整数 TWD。地址快照字段为联系人、电话、市/区、交付方式、地址、详细地址和经纬度。客户端传入的金额/距离不会被使用。用户详情响应为 `order,images,logs,rider,deliveryPinCode?`,其中 PIN 仅在订单启用时向订单用户返回;骑手详情永不返回 PIN,用户仅在 `ACCEPTED`、`PICKED_UP` 阶段获得骑手位置。
+用户列表摘要字段固定为:`id,orderNo,serviceType,status,packageType,deliveryMode,scheduledPickupStartAt,scheduledPickupEndAt,pickupAddress,pickupDetailAddress,deliveryAddress,deliveryDetailAddress,estimatedDurationSeconds,amount,currency,deliveredAt,createTime`。列表不返回联系人、电话、精确坐标、照片、日志或计价审计字段。
+
+报价响应 data:`serviceType,pricingId,startTime,endTime,distanceMeters,distanceSource,estimatedDurationSeconds?,startingDistance,startingFare,distance,freight,billableDistance,distanceFee,amount,currency,pricingVersion`。`billableDistance` 为按外卖规则处理 0.5 公里边界后的计费公里数,`distanceFee` 与 `amount` 为整数 TWD。地址快照字段为联系人、电话、市/区、交付方式、地址、详细地址和经纬度。客户端传入的金额/距离不会被使用。用户创建和详情响应的 `data` 直接为订单详情字段,照片分别为 `senderImageUrls,pickupImageUrls,deliveryImageUrls`,不返回原始状态日志;`deliveryPinCode` 仅在启用时向订单用户返回,用户仅在 `ACCEPTED`、`PICKED_UP` 阶段获得骑手位置。
 
 ## 骑手端
 
@@ -46,14 +48,17 @@
 
 | 方法 | 路径 | 请求/说明 |
 |---|---|---|
-| GET | `/system/flashDelivery/rider/orders/available` | `pageNum,pageSize,serviceType?`;加急优先,仅返回下述接单前安全字段 |
-| GET | `/system/flashDelivery/rider/orders/mine` | `pageNum,pageSize,status?,scene?`;`scene=pickup/delivering/completed/cancelled`;仅本人任务 |
-| GET | `/system/flashDelivery/rider/orders/{id}` | 未接单仅返回接单前安全字段;接单后仅订单骑手可见完整信息 |
-| POST | `/system/flashDelivery/rider/orders/{id}/accept` | 原子抢单,成功返回完整详情 |
+| GET | `/system/flashDelivery/rider/orders` | `page,size,tab,longitude?,latitude?`;参数方式与骑手外卖列表一致,`tab=newTask/toPickup/delivering/completed/cancelled`;坐标用于新任务附近范围、取件点距离和排序 |
+| GET | `/system/flashDelivery/rider/orders/{id}` | `data` 直接为稳定的骑手订单详情;未接单隐藏敏感字段,接单后仅订单骑手可见完整履约信息 |
+| POST | `/system/flashDelivery/rider/orders/{id}/accept` | 原子抢单,成功后 `data` 直接返回骑手订单详情 |
 | POST | `/system/flashDelivery/rider/orders/{id}/pickup` | `{"imageUrls":["https://.../pickup.jpg"]}`;至少一张 |
 | POST | `/system/flashDelivery/rider/orders/{id}/deliver` | `{"imageUrls":["https://.../delivery.jpg"],"pinCode":"4821"}`;图片至少一张,启用 PIN 时必须正确 |
 
-接单前安全字段固定为:`id,orderNo,serviceType,status,packageType,packageSize,deliveryMode,scheduledPickupStartAt,scheduledPickupEndAt,pickupCity,pickupArea,deliveryCity,deliveryArea,pickupLatitudeApprox,pickupLongitudeApprox,deliveryLatitudeApprox,deliveryLongitudeApprox,distanceMeters,estimatedDurationSeconds,amount,currency,createTime`。近似经纬度只保留两位小数;不返回用户 ID、联系人、电话、完整文字地址、精确经纬度、备注、PIN、幂等请求号、凭证或日志。抢单成功后才向中单骑手返回履约业务详情。
+骑手页签状态映射:`newTask=WAITING_ACCEPTANCE`、`toPickup=ACCEPTED`、`delivering=PICKED_UP`、`completed=DELIVERED+COMPLETED`、`cancelled=CANCELLED`。除 `newTask` 外只返回当前骑手本人任务;闪送没有 `refund` 页签。
+
+骑手列表摘要字段固定为:`id,orderNo,serviceType,status,packageType,packageSize,deliveryMode,scheduledPickupStartAt,scheduledPickupEndAt,pinRequired,pickupAddress,pickupDetailAddress,deliveryAddress,deliveryDetailAddress,pickupDistanceMeters,distanceMeters,estimatedDurationSeconds,amount,currency,createTime`。`newTask` 分页 data 在 `records,total,current,size` 外增加 `nearbyTaskCount,highestOrderAmount`;不返回尖峰倍率或骑手收入字段。
+
+骑手接单前可按原型查看完整取送文字地址,但不返回用户 ID、联系人、电话、实际 PIN、精确经纬度、备注、幂等请求号、履约凭证或日志。抢单成功后才向中单骑手返回完整联系方式、坐标和有权限查看的照片数组。骑手详情在接单前后使用同一个直接 DTO,不返回 `{order,images,logs}` 包装,也不要求 App 判断 `data.order`。
 
 ## 平台端
 

+ 40 - 3
specs/024-flash-delivery/design.md

@@ -53,8 +53,7 @@ ruoyi-system
 
 ### 3.2 骑手端
 
-- `GET /system/flashDelivery/rider/orders/available`
-- `GET /system/flashDelivery/rider/orders/mine`
+- `GET /system/flashDelivery/rider/orders`
 - `GET /system/flashDelivery/rider/orders/{id}`
 - `POST /system/flashDelivery/rider/orders/{id}/accept`
 - `POST /system/flashDelivery/rider/orders/{id}/pickup`
@@ -154,7 +153,7 @@ COMPLETED
 - 用户订单查询和操作按 `order_id + user_id` 校验。
 - 骑手履约操作按 `order_id + rider_id + expected_status` 校验。
 - 骑手抢单使用数据库条件更新,避免双抢。
-- 待抢订单隐藏完整电话与详细门牌;抢单后才向订单骑手展示
+- 待抢订单按原型显示完整取送文字地址,但隐藏联系人、电话、实际 PIN、精确坐标和内部字段;抢单后才向订单骑手展示完整履约信息
 - 地址操作按 `address_id + user_id` 校验,客户端 `userId` 不参与归属判断。
 - Controller 使用明确 DTO、`@RequestBody`、`@RequestParam`、`@PathVariable` 和 `@RequestHeader`,不接收 Map。
 - 地图密钥不返回客户端、不写日志;业务错误使用国际化消息。
@@ -177,3 +176,41 @@ COMPLETED
 ## 9. 明确延期内容
 
 支付、退款、分账、骑手收入、代购、垫付、商品金额、精确重量、件数、自动派单、动态附近骑手数、预计接单时间以及用户端、骑手端和商家端页面均不在本期范围。
+
+## 10. App 订单列表精简增量(2026-09-01)
+
+### 10.1 设计选择
+
+采用单一骑手列表接口,查询参数与现有骑手外卖订单列表保持一致。该方案让 App 的两类配送列表共享 `page、size、tab、longitude、latitude` 的调用方式,同时由服务端完成页签到状态的映射。原 `/available` 与 `/mine` 拆分接口、`scene` 与 `serviceType` 组合筛选不再保留。
+
+没有采用“保留两个接口只改参数名”,因为 App 仍需维护两套请求和响应;也没有采用“列表继续返回完整详情对象”,因为列表页面只需要卡片字段,完整订单信息已有独立详情接口。
+
+### 10.2 用户列表
+
+- `GET /system/flashDelivery/orders?page=1&size=10`
+- 只查询当前用户,按创建时间倒序混合返回各状态订单。
+- 列表不接受 `status`、`scene` 或 `serviceType`,页面无需为了简单卡片组装筛选条件。
+- 使用用户列表摘要 DTO,只包含卡片展示所需的订单标识、服务/包裹、状态、取送文字地址、配送时段、预计时长、金额和关键展示时间;完整联系方式、精确坐标和照片由详情接口按明确字段返回,原始状态日志不向 App 返回。
+
+### 10.3 骑手列表
+
+- `GET /system/flashDelivery/rider/orders?page=1&size=10&tab=newTask&longitude=121.5&latitude=25.0`
+- 参数名、默认分页和坐标用途与骑手外卖订单列表保持一致;经纬度用于 `newTask` 的附近范围、取件点距离和排序,其他页签忽略坐标。
+- `newTask -> WAITING_ACCEPTANCE`;`toPickup -> ACCEPTED`;`delivering -> PICKED_UP`;`completed -> DELIVERED + COMPLETED`;`cancelled -> CANCELLED`。除 `newTask` 外均只查询当前骑手本人。
+- 闪送没有退款流程,因此不接受外卖列表的 `refund` 页签。
+- 列表使用统一卡片摘要 DTO,包含订单标识、服务类型、状态、包裹类别/重量档、配送方式/预约时段、是否需要 PIN、完整取送文字地址、取件点距离、路线距离、预计时长、订单金额和创建时间。
+- `newTask` 分页响应额外返回附近任务总数与最高订单金额,用于原型顶部摘要;不返回已移除的尖峰倍率,也不将订单金额表述为尚未实现的骑手收入。
+- 接单前不返回联系人、电话、实际 PIN、精确坐标、用户备注、图片凭证、状态日志、用户 ID、幂等号或计价审计字段。接单成功后,详情接口仅向中单骑手返回完整履约信息。
+
+### 10.4 App 详情响应
+
+- 用户创建订单、用户订单详情、骑手订单详情和骑手接单成功响应的 `data` 直接返回订单详情字段,不再使用 `{order,images,logs}` 包装。
+- 寄件、取件和送达照片分别使用 `senderImageUrls`、`pickupImageUrls`、`deliveryImageUrls`,避免 App 再按通用图片记录的类型分组。
+- App 详情不返回原始状态日志;页面使用 `status`、`acceptedAt`、`pickedUpAt`、`deliveredAt`、`completedAt` 和 `cancelledAt` 展示进度。平台详情继续保留 `{order,images,logs}` 供审计。
+- 骑手接单前后使用同一个详情 DTO:接单前隐藏联系人、电话、实际 PIN、精确坐标和履约凭证,接单后只向中单骑手补齐可见字段,`data` 顶层形状保持不变。
+
+### 10.5 兼容和错误处理
+
+- App 与后端同步切换到新接口,不保留测试阶段旧 `/available`、`/mine` 路由或旧参数兼容层。
+- `page`、`size` 或 `tab` 非法时返回国际化业务错误;坐标必须成对出现并通过经纬度范围校验。
+- 列表必须先按页签和角色过滤,再由数据库分页;禁止查出完整集合后在 Java 或客户端过滤。

+ 18 - 12
specs/024-flash-delivery/spec.md

@@ -4,7 +4,7 @@
 
 **创建日期**:2026-08-31
 
-**状态**:平台前端与外卖同规则时段运价调整已实现并通过约定验证
+**状态**:平台前端与外卖同规则时段运价调整已验证;App 列表精简设计已确认、待实现
 
 **输入**:基于蓝湖“闪送”分组 7 个设计页面及 2026-08-24 用户端/骑手端补充原型,实现帮送、帮取、加急送的完整非支付业务闭环,包括共享地址簿、路线报价、包裹信息、立即/预约配送、可选 PIN 交付、创建订单、骑手主动抢单、取件、送达、用户签收、平台配置与介入。
 
@@ -33,15 +33,15 @@
 
 ### 用户故事 2:骑手从闪送列表主动抢单并完成配送(优先级:P1)
 
-骑手在闪送待接单列表中查看可抢订单,主动抢单后依次上传取件和送达图片,完成实际配送。
+骑手通过与骑手外卖订单一致的单一分页列表和页签参数查看新任务、待取件、配送中、已完成及已取消任务,主动抢单后依次上传取件和送达图片,完成实际配送。
 
 **优先级原因**:第一版明确采用骑手主动抢单,不实现自动派单;抢单与配送状态流转是业务闭环的核心。
 
-**独立测试**:创建一笔待接单订单,由两个骑手并发抢单,验证只有一个骑手成功;成功骑手上传取件和送达图片后,订单依次进入已取件和已送达状态。
+**独立测试**:使用 `page、size、tab、longitude、latitude` 查询骑手闪送列表,验证五个页签的状态映射、本人订单边界、附近任务距离和接单前字段;再由两个骑手并发抢同一订单,验证只有一个骑手成功,成功骑手上传取件和送达图片后订单依次进入已取件和已送达状态。
 
 **验收场景**:
 
-1. **假如** 同时存在普通和加急待接订单,**当** 骑手查询闪送列表,**那么** 加急订单优先展示,其余订单按发布时间排序
+1. **假如** 骑手传入 `tab=newTask` 和当前位置,**当** 查询闪送列表,**那么** 系统只返回当前可抢任务,并按与骑手外卖新任务列表一致的附近范围和距离规则处理
 2. **假如** 两名骑手同时抢同一订单,**当** 两个请求并发到达,**那么** 只有一名骑手成功,另一名收到订单已被接走的业务结果。
 3. **假如** 骑手尚未抢到订单,**当** 其尝试确认取件或送达,**那么** 系统拒绝操作且不泄露完整联系方式。
 4. **假如** 已接单骑手未提交取件图片,**当** 其确认取件,**那么** 系统拒绝状态变更。
@@ -49,7 +49,9 @@
 6. **假如** 图片要求已满足,**当** 订单骑手按顺序确认取件和送达,**那么** 系统保存凭证、操作人和时间并完成对应状态变更。
 7. **假如** 订单启用 PIN 交付,**当** 骑手提交错误 PIN,**那么** 系统拒绝送达且不保存送达图片或改变状态。
 8. **假如** 订单启用 PIN 交付,**当** 骑手提交正确 PIN 和送达图片,**那么** 系统验证 PIN 后进入已送达状态。
-9. **假如** 骑手尚未接单,**当** 查看列表或详情,**那么** 仅返回包裹、时段、路线区域和报价等安全摘要,不返回完整门牌、联系人、电话、PIN 或内部字段。
+9. **假如** 骑手尚未接单,**当** 查看列表或详情,**那么** 系统按原型返回完整取送文字地址、包裹、时段、路线、金额和是否需要 PIN 等接单判断信息,但不返回联系人、电话、实际 PIN、精确坐标或内部字段。
+10. **假如** 骑手切换 `toPickup`、`delivering`、`completed` 或 `cancelled` 页签,**当** 查询列表,**那么** 系统只返回当前骑手本人且符合页签状态映射的任务。
+11. **假如** 骑手查看列表顶部摘要,**当** 当前页签为 `newTask`,**那么** 系统返回附近任务总数和最高订单金额,不返回尖峰倍率或骑手收入字段。
 
 ---
 
@@ -72,7 +74,7 @@
 
 ### 用户故事 4:用户跟踪、取消和签收自己的订单(优先级:P1)
 
-用户查看自己的闪送订单与状态日志,可以在允许阶段取消订单,并在骑手送达后确认签收。
+用户查看自己的闪送订单与履约进度,可以在允许阶段取消订单,并在骑手送达后确认签收。
 
 **优先级原因**:用户需要了解履约进度,并对尚未实际取件的订单保留取消能力。
 
@@ -85,6 +87,7 @@
 3. **假如** 骑手已确认送达,**当** 订单用户确认签收,**那么** 订单进入已完成状态。
 4. **假如** 骑手送达后用户 24 小时未确认,**当** 自动完成任务执行,**那么** 订单进入已完成状态并记录自动操作日志。
 5. **假如** 用户访问其他用户的订单,**当** 其查询详情、取消或签收,**那么** 系统拒绝访问。
+6. **假如** 用户查询订单列表,**当** 仅提交 `page` 和 `size`,**那么** 系统按创建时间倒序返回本人各状态订单的轻量摘要,不要求客户端提交 `scene`、`status` 或 `serviceType`。
 
 ---
 
@@ -132,7 +135,7 @@
 - 地图路线结果缺少有效距离时按路线失败处理并降级为直线距离。
 - 创建订单时当前配置与先前报价时不同,以创建时服务端重新计算结果为准。
 - 待接单列表仅返回待接单订单;已取消或已被抢走的订单不得继续出现在新查询结果中。
-- 待抢订单列表隐藏完整电话和门牌信息;骑手抢单成功后才能读取配送所需的完整快照
+- 待抢订单列表按原型显示完整取送文字地址,但隐藏联系人、电话、实际 PIN、精确坐标和内部字段;抢单成功后订单骑手才能读取履约所需的完整联系方式与坐标
 - 骑手第一版不能自行放弃已抢订单,需要平台介入处理。
 - 已完成和已取消为终态,不允许再次变更。
 - 自动完成任务与用户确认、平台完成并发时,只允许一个状态变更成功且不得重复写入完成副作用。
@@ -157,8 +160,8 @@
 - **FR-011**:闪送订单不得复用餐饮订单或打车订单数据模型。
 - **FR-012**:订单必须保存包裹类别和机车可载重量档,重量档为 `SMALL`(不超过 5kg)、`MEDIUM`(不超过 12kg)或 `LARGE`(不超过 20kg);不保存精确重量或件数。
 - **FR-013**:订单必须支持用户备注,但备注不参与计价。
-- **FR-014**:骑手必须通过独立闪送待接单列表主动抢单,第一阶段不实现自动派单。
-- **FR-015**:待接单列表必须按加急优先、创建时间次优先的顺序返回
+- **FR-014**:骑手必须通过统一闪送订单列表的 `newTask` 页签主动抢单,第一阶段不实现自动派单。
+- **FR-015**:骑手闪送列表必须复用骑手外卖订单列表的查询参数名称和分页习惯:`page`、`size`、`tab`、`longitude`、`latitude`;不得再拆分为 `available`、`mine` 或叠加 `scene`、`status`、`serviceType` 筛选
 - **FR-016**:骑手抢单必须使用原子条件更新,确保同一订单最多由一名骑手抢到。
 - **FR-017**:订单状态必须包括待接单、已接单、已取件、已送达、已完成和已取消。
 - **FR-018**:只有抢到订单的骑手能够确认取件和送达。
@@ -172,7 +175,7 @@
 - **FR-026**:每次有效状态变更必须记录变更前状态、变更后状态、操作人类型、操作人 ID、原因和时间。
 - **FR-027**:所有状态变更必须校验当前状态、业务归属和操作角色,并防止并发覆盖。
 - **FR-028**:用户只能查询、取消和签收自己的闪送订单。
-- **FR-029**:骑手在抢单前只能看到履约判断所需的脱敏信息,抢单成功后才能查看完整联系方式和门牌信息
+- **FR-029**:骑手在抢单前可查看完整取送文字地址及履约判断所需的订单摘要,但不得获得联系人、电话、实际 PIN、精确坐标或内部字段;抢单成功后才能查看完整联系方式和坐标
 - **FR-030**:闪送必须与现有收货场景共用 `info_address` 地址数据。
 - **FR-031**:统一地址接口必须要求登录身份,并对详情、修改、删除和置顶执行地址所有权校验。
 - **FR-032**:地址列表必须支持按当前用户的姓名、电话和地址关键词搜索,并支持置顶排序。
@@ -188,8 +191,8 @@
 - **FR-042**:用户可选择是否启用 4 位数字交付 PIN;启用后骑手必须同时提交正确 PIN 和至少一张送达图片。
 - **FR-043**:PIN 只对订单用户和有权限的平台管理员可见,不得返回给待接单或已接单骑手,也不得写入业务日志。
 - **FR-044**:创建订单可提交 1 至 9 张可选寄件图片;凭证类型扩展为 `SENDER`、`PICKUP`、`DELIVERY` 并记录操作人类型。
-- **FR-045**:用户和骑手列表必须支持页面状态分组并在服务端完成分页,禁止先分页后由客户端过滤多个底层状态
-- **FR-046**:用户和骑手详情必须使用角色专用响应视图,不得直接序列化订单实体、客户端幂等号、内部用户 ID 或计价审计字段
+- **FR-045**:用户订单列表必须只接收 `page` 和 `size`,按创建时间倒序返回本人全部状态的轻量摘要;骑手订单列表必须按 `tab` 在服务端映射底层状态并完成分页,禁止先分页后由客户端过滤。
+- **FR-046**:用户列表、骑手列表和角色详情必须分别使用专用响应视图。App 详情响应的 `data` 必须直接是订单详情,不得再套 `order`、`images` 或 `logs`;照片使用 `senderImageUrls`、`pickupImageUrls`、`deliveryImageUrls` 等明确字段,原始状态日志只允许平台审计详情返回
 - **FR-047**:骑手接单后,用户可读取骑手昵称、头像和评分等公开摘要;实时位置只在配送进行状态向订单用户返回。
 - **FR-048**:路线距离不得超过 40 公里;超过限制时报价和创建均拒绝。
 - **FR-049**:平台管理前端必须提供“闪送管理”父菜单,并提供“价格配置”和“闪送订单”两个子页面。
@@ -201,6 +204,9 @@
 - **FR-055**:平台取消必须要求非空原因和二次确认;平台完成必须二次确认。操作成功后刷新服务端数据,操作失败时保留当前页面并显示后端错误。
 - **FR-056**:平台前端新增的全部用户可见文本必须通过 Vue i18n 提供简体中文、繁体中文、英文和越南文,不得硬编码单一语言文本。
 - **FR-057**:平台前端必须沿用现有 Vue 2、Element UI、若依请求封装、动态菜单和 `v-hasPermi` 体系,不新增重复的状态管理或 UI 框架。
+- **FR-058**:骑手列表 `tab` 只接受 `newTask`、`toPickup`、`delivering`、`completed` 和 `cancelled`,分别映射待接单、已接单、已取件、已送达/已完成和已取消;闪送不提供外卖退款页签。
+- **FR-059**:骑手 `newTask` 列表必须返回取件点距离、路线距离、预计时长、订单金额、包裹类别、重量档、配送方式、预约时段、完整取送文字地址和是否需要 PIN,并返回附近任务总数与最高订单金额;不得返回已移除的尖峰倍率或尚未实现的骑手收入。
+- **FR-060**:用户创建订单、用户详情、骑手详情和骑手接单成功响应必须使用直接且稳定的 App 订单详情结构;权限差异只影响敏感字段是否返回,不得改变 `data` 的顶层形状,也不得要求 App 通过 `data.order` 是否存在判断响应类型。
 
 ### 关键实体