Pārlūkot izejas kodu

feat(闪送): 详情收件人视角开放其他收货站文字地址

- v2 详情中收件人看他人的收货站:文字地址、备注、交接方式与列表同口径开放;联系人、电话、坐标仍不返回
- 按站收货码、凭证图仍仅发起人与本站收件人可见
- 文档同步 app-api 与 v2 handoff 的收件人可见性说明及验收清单
qmj 4 dienas atpakaļ
vecāks
revīzija
b5bf48a4c3

+ 1 - 1
docs/flash-delivery-app-api.md

@@ -1203,7 +1203,7 @@ POST /system/flashDelivery/rider/orders/stops/deliver
 
 v2 订单即使只有一个收货站,也必须使用上述逐站送达接口并传 `stopId`;旧整单送达接口拒绝 v2 订单。每次送达只接受详情中 `currentTargetStopId` 对应的待送站;需调整送达顺序时,骑手通过原目标调整入口选站,v2 的自主调整规则以文末 2026-10-15 修订为准。末站送达后重复请求可安全返回,不会再次保存凭证或通知。全部收货站完成才进入 `DELIVERED`;确认收货或系统/平台完成进入 `COMPLETED` 后才生成一次骑手收入账单。
 
-`stops[].id` 是站点 ID。启用 PIN 时,v2 详情在对应收货站的 `deliveryPinCode` 返回各站独立收货码;发起人可见全部,系统内匹配的收件人仅能看到自己的站点收货码,骑手看不到。收件人列表卡片展示自己的收货地址,详情隐藏其他收货站的联系人和精确地址。匹配不到系统用户时,仍保留联系人电话和按站收货码,由发起人线下告知;本阶段不实现逐站收件人推送。v2 订单级 `deliveryPinCode` 不再用作送达码。订单列表和详情提供 `deliveryStopCount`、`deliveredStopCount` 供展示进度。
+`stops[].id` 是站点 ID。启用 PIN 时,v2 详情在对应收货站的 `deliveryPinCode` 返回各站独立收货码;发起人可见全部,系统内匹配的收件人仅能看到自己的站点收货码,骑手看不到。收件人卡片主位的收货地址指向本人站点;其他收货站的文字地址与备注对寄件、收件同口径返回(2026-10-15 放开),联系人和坐标仍隐藏。匹配不到系统用户时,仍保留联系人电话和按站收货码,由发起人线下告知;本阶段不实现逐站收件人推送。v2 订单级 `deliveryPinCode` 不再用作送达码。订单列表和详情提供 `deliveryStopCount`、`deliveredStopCount` 供展示进度。
 
 v2 待接单订单修改站点使用两个新接口,token 在请求头,其余业务参数全部在 JSON body:
 

+ 2 - 2
docs/flash-delivery-v2-frontend-handoff.md

@@ -84,7 +84,7 @@
 
 卡片及详情同时显示 `已取件 {pickedUpStopCount}/{pickupStopCount} · 已送达 {deliveredStopCount}/{deliveryStopCount}`,文本按 App 四语言规范接入。例如取1→取2→送1→取3→送2:送1后显示“已取件 2/3 · 已送达 1/2”,仍在待取件;取3后显示“已取件 3/3 · 已送达 1/2”,进入配送中;送2后进入已送达。不要把它拆成两条订单或同时放入两个 Tab,角标计订单数量而非站点数,继续使用原列表及 `GET /system/flashDelivery/rider/orderCount`。列表展示进度;进入详情后使用 `currentTargetStopId` 突出下一站的取/送类型。
 
-v2 的订单级 `deliveryPinCode` 为空,收货码在各个 DELIVERY 站的 `stops[].deliveryPinCode`。发起人可查看全部收货码;已在系统内匹配的收件人只能查看自己站的收货码及联系人、精确地址和凭证;骑手看不到任何实际收货码。未匹配系统用户的收货站仍可下单,但此人不会进入“我收的”列表,也不会收到 App 推送;发起人需自行告知该站收货码。**逐站收件人通知本期暂缓。**
+v2 的订单级 `deliveryPinCode` 为空,收货码在各个 DELIVERY 站的 `stops[].deliveryPinCode`。发起人可查看全部收货码;已在系统内匹配的收件人只能查看自己站的收货码、联系人、坐标和凭证,其他站的文字地址与备注同口径开放(2026-10-15);骑手看不到任何实际收货码。未匹配系统用户的收货站仍可下单,但此人不会进入“我收的”列表,也不会收到 App 推送;发起人需自行告知该站收货码。**逐站收件人通知本期暂缓。**
 
 用户端取消按钮以 `canUserCancel` 为准;任一取货站已取货后不可自助取消。确认收货入口只在整单 `DELIVERED` 后提供;系统仍会检查全部收货站是否真的已送达。骑手收入账单只在订单进入 `COMPLETED` 时生成一次。
 
@@ -144,7 +144,7 @@ Content-Type: application/json
 1. 单取单送和多取多送都走 v2 报价/创建;收货站只有一站时,送达仍提供 `stopId`。
 2. 验证取1→取2→送1→取3→送2,以及骑手自主改为先取完再送;送1后 `ACCEPTED`、进度 2/3 与 1/2,取3后 `PICKED_UP`,送2后 `DELIVERED`。五个 Tab 和名称不变,不能提前确认完成或记账。
 3. 修改第二个收货站后,其他站、订单级物品和原运价仍在;保存后旧站点 ID/PIN 不再使用。
-4. 发起人看全部收货码,匹配的第二站收件人只看自己的地址、联系人、凭证和 PIN;骑手看不到 PIN;未匹配用户不出现 App 收件人入口。
+4. 发起人看全部收货码,匹配的第二站收件人看得到全部站的文字地址与备注,但联系人、坐标、凭证和 PIN 只有自己站可见;骑手看不到 PIN;未匹配用户不出现 App 收件人入口。
 5. 发起人收到每站一次进度消息并能按订单号打开详情;收件人没有逐站推送。真实设备推送和 App 页面尚需联调。
 
 现有单点、支付及其他旧接口以 [原闪送 App API 文档](flash-delivery-app-api.md) 为准。数据库结构和不同环境的执行方式见 [10 月 14 日 SQL 说明](../updatesql/sql.md);本次问题修复没有额外字段变更;2026-10-14 测试库已按旧版增量路径完成结构与字典更新,其他环境仍需按 SQL 说明执行。

+ 3 - 3
ruoyi-admin/src/main/java/com/ruoyi/app/flashdelivery/service/FlashDeliveryApplicationService.java

@@ -1480,9 +1480,9 @@ public class FlashDeliveryApplicationService {
                 if (sender || Objects.equals(viewerId, stop.getReceiverUserId())) {
                     stopView.setDeliveryPinCode(Boolean.TRUE.equals(order.getPinRequired()) ? stop.getDeliveryPinCode() : null);
                 } else if (v2Receiver) {
-                    stopView.setName(null); stopView.setPhone(null); stopView.setAddress(null); stopView.setAddressDetail(null);
-                    stopView.setHandoffMethod(null); stopView.setLongitude(null); stopView.setLatitude(null);
-                    stopView.setRemark(null); stopView.setImageUrls(List.of());
+                    // 他人收货站开放文字地址、备注与交接方式(与列表口径一致),联系人、电话、坐标仍不返回。
+                    stopView.setName(null); stopView.setPhone(null);
+                    stopView.setLongitude(null); stopView.setLatitude(null);
                 }
             }
             if (v2Receiver) {

+ 2 - 1
ruoyi-admin/src/test/java/com/ruoyi/app/flashdelivery/service/FlashDeliveryV2Test.java

@@ -357,7 +357,8 @@ class FlashDeliveryV2Test {
         assertEquals("2222", receiver.at("/stops/3/deliveryPinCode").asText());
         assertTrue(receiver.at("/stops/2/deliveryPinCode").isMissingNode() || receiver.at("/stops/2/deliveryPinCode").isNull());
         assertNull(f.service.userDetail(32L, 10L).getStops().get(2).getPhone());
-        assertNull(f.service.userDetail(32L, 10L).getStops().get(2).getAddress());
+        // 他人收货站开放文字地址(与列表口径一致),联系人与坐标仍不返回。
+        assertEquals("address 2", f.service.userDetail(32L, 10L).getStops().get(2).getAddress());
         assertEquals("0911111113", f.service.userDetail(32L, 10L).getDelivery().getPhone());
         var rider = json.valueToTree(f.service.riderDetail(8L, 10L));
         assertTrue(rider.at("/stops/2/deliveryPinCode").isMissingNode() || rider.at("/stops/2/deliveryPinCode").isNull());