Forráskód Böngészése

制定闪送 App 订单接口精简计划

qmj 3 napja
szülő
commit
8a3ea64151
2 módosított fájl, 258 hozzáadás és 1 törlés
  1. 248 1
      specs/024-flash-delivery/plan.md
  2. 10 0
      specs/024-flash-delivery/tasks.md

+ 248 - 1
specs/024-flash-delivery/plan.md

@@ -262,7 +262,7 @@ foodie-admin-vue/
 Set-Location E:\QtwCode\foodie\foodie_server
 $env:JAVA_HOME='C:\Users\qmj\.jdks\graalvm-jdk-21.0.7'
 $env:PATH="$env:JAVA_HOME\bin;$env:PATH"
-mvn -pl ruoyi-admin -am -Dtest='FlashDeliveryPricingCalculatorTest,FlashDeliveryApplicationServiceTest,FlashDeliveryControllerContractTest,FlashDeliveryOrderViewTest,FlashDeliveryAvailableOrderViewTest,FlashDeliveryI18nContractTest' -Dsurefire.failIfNoSpecifiedTests=false test
+mvn -pl ruoyi-admin -am -Dtest='FlashDeliveryPricingCalculatorTest,FlashDeliveryApplicationServiceTest,FlashDeliveryControllerContractTest,FlashDeliveryOrderViewTest,FlashDeliveryRiderOrderListViewTest,FlashDeliveryI18nContractTest' -Dsurefire.failIfNoSpecifiedTests=false test
 mvn -pl ruoyi-admin -am -DskipTests package
 git diff --check
 
@@ -272,3 +272,250 @@ npx eslint --no-ignore src/api/flashDelivery/index.js src/api/flashDelivery/cont
 npm run build:prod
 git diff --check
 ```
+
+# 闪送 App 订单列表与详情精简 Implementation Plan
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** 将用户端和骑手端闪送订单接口收敛为与页面一致的轻量列表与直接详情响应,并让骑手列表复用外卖订单的分页、页签和位置参数。
+
+**Architecture:** Controller 只暴露新的显式查询参数;`FlashDeliveryApplicationService` 在数据库分页前完成用户归属、骑手页签、预约可抢和附近距离条件。列表分别使用用户/骑手卡片 DTO,App 详情使用继承订单业务字段的直接 DTO;平台审计详情继续独立保留实体、图片和日志。
+
+**Tech Stack:** JDK 21、Spring Boot、MyBatis-Plus、MySQL、JUnit 5、Mockito、Lombok。
+
+## Global Constraints
+
+- 不新建分支或 worktree,在当前 `test` 分支连续实施。
+- 不保留开发测试阶段的 `/orders/available`、`/orders/mine`、`scene`、`status`、`serviceType` 兼容入口。
+- 用户和骑手身份只从 `@RequestHeader String token` 解析;查询参数全部显式使用 `@RequestParam`。
+- App 列表和详情禁止返回实体、幂等号、内部用户 ID、计价审计字段或原始状态日志。
+- 骑手接单前显示完整取送文字地址,但不返回联系人、电话、实际 PIN、精确坐标或履约图片。
+- 后端业务错误同步 `messages.properties`、`messages_zh_CN.properties`、`messages_zh_TW.properties`、`messages_en_US.properties` 和 `messages_vi.properties`。
+- 不执行数据库迁移;本次接口精简不需要表结构变更。
+
+---
+
+### Task 1: 固定 Controller 与 DTO 契约
+
+**Files:**
+- Modify: `ruoyi-admin/src/test/java/com/ruoyi/app/flashdelivery/controller/FlashDeliveryControllerContractTest.java`
+- Delete: `ruoyi-admin/src/test/java/com/ruoyi/app/flashdelivery/dto/FlashDeliveryAvailableOrderViewTest.java`
+- Create: `ruoyi-admin/src/test/java/com/ruoyi/app/flashdelivery/dto/FlashDeliveryRiderOrderListViewTest.java`
+- Modify: `ruoyi-admin/src/test/java/com/ruoyi/app/flashdelivery/dto/FlashDeliveryOrderViewTest.java`
+- Create: `ruoyi-admin/src/main/java/com/ruoyi/app/flashdelivery/dto/FlashDeliveryUserOrderListView.java`
+- Create: `ruoyi-admin/src/main/java/com/ruoyi/app/flashdelivery/dto/FlashDeliveryRiderOrderListView.java`
+- Create: `ruoyi-admin/src/main/java/com/ruoyi/app/flashdelivery/dto/FlashDeliveryRiderOrderPageView.java`
+- Modify: `ruoyi-admin/src/main/java/com/ruoyi/app/flashdelivery/dto/FlashDeliveryOrderDetailView.java`
+- Delete: `ruoyi-admin/src/main/java/com/ruoyi/app/flashdelivery/dto/FlashDeliveryAvailableOrderView.java`
+- Delete: `ruoyi-admin/src/main/java/com/ruoyi/app/flashdelivery/dto/FlashDeliveryImageView.java`
+- Delete: `ruoyi-admin/src/main/java/com/ruoyi/app/flashdelivery/dto/FlashDeliveryLogView.java`
+
+**Interfaces:**
+- Produces: `FlashDeliveryUserOrderListView` for user cards.
+- Produces: `FlashDeliveryRiderOrderListView` for all rider tabs.
+- Produces: `FlashDeliveryRiderOrderPageView(records,total,current,size,nearbyTaskCount,highestOrderAmount)`.
+- Produces: direct `FlashDeliveryOrderDetailView extends FlashDeliveryOrderView` with `senderImageUrls,pickupImageUrls,deliveryImageUrls,rider,deliveryPinCode`.
+
+- [ ] **Step 1: Write failing reflection and whitelist tests**
+
+```java
+Method userOrders = FlashDeliveryUserController.class.getMethod(
+        "orders", String.class, int.class, int.class);
+Method riderOrders = FlashDeliveryRiderController.class.getMethod(
+        "orders", String.class, int.class, int.class, String.class,
+        BigDecimal.class, BigDecimal.class);
+assertThrows(NoSuchFieldException.class,
+        () -> FlashDeliveryOrderDetailView.class.getDeclaredField("order"));
+assertTrue(riderFields.containsAll(Set.of("pickupAddress", "deliveryAddress",
+        "pickupDistanceMeters", "pinRequired")));
+```
+
+- [ ] **Step 2: Run tests and verify the old contract fails**
+
+```powershell
+$env:JAVA_HOME='C:\Users\qmj\.jdks\graalvm-jdk-21.0.7'
+$env:PATH="$env:JAVA_HOME\bin;$env:PATH"
+mvn -pl ruoyi-admin -am -Dtest='FlashDeliveryControllerContractTest,FlashDeliveryOrderViewTest,FlashDeliveryRiderOrderListViewTest' -Dsurefire.failIfNoSpecifiedTests=false test
+```
+
+Expected: compilation or reflection failure because the old controllers and wrapper DTO still exist.
+
+- [ ] **Step 3: Add the minimal DTO types**
+
+```java
+@Data
+public class FlashDeliveryOrderDetailView extends FlashDeliveryOrderView {
+    private List<String> senderImageUrls = List.of();
+    private List<String> pickupImageUrls = List.of();
+    private List<String> deliveryImageUrls = List.of();
+    private FlashDeliveryRiderSummaryView rider;
+    private String deliveryPinCode;
+}
+```
+
+`FlashDeliveryUserOrderListView` 固定卡片字段为订单标识、服务/包裹、状态、配送方式/预约时段、取送文字地址、预计时长、金额、送达时间和创建时间。`FlashDeliveryRiderOrderListView` 固定增加重量档、`pinRequired`、`pickupDistanceMeters` 和路线距离。分页 DTO 只使用上述六个分页/摘要属性。
+
+- [ ] **Step 4: Run DTO tests**
+
+```powershell
+mvn -pl ruoyi-admin -am -Dtest='FlashDeliveryControllerContractTest,FlashDeliveryOrderViewTest,FlashDeliveryRiderOrderListViewTest' -Dsurefire.failIfNoSpecifiedTests=false test
+```
+
+Expected: DTO whitelist tests pass; controller reflection test remains red until Task 2.
+
+### Task 2: 实现轻量列表、统一骑手页签和直接详情
+
+**Files:**
+- Modify: `ruoyi-admin/src/main/java/com/ruoyi/app/flashdelivery/controller/FlashDeliveryUserController.java`
+- Modify: `ruoyi-admin/src/main/java/com/ruoyi/app/flashdelivery/controller/FlashDeliveryRiderController.java`
+- Modify: `ruoyi-admin/src/main/java/com/ruoyi/app/flashdelivery/service/FlashDeliveryApplicationService.java`
+- Modify: `ruoyi-admin/src/test/java/com/ruoyi/app/flashdelivery/service/FlashDeliveryApplicationServiceTest.java`
+- Modify: `ruoyi-admin/src/main/resources/i18n/messages.properties`
+- Modify: `ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties`
+- Modify: `ruoyi-admin/src/main/resources/i18n/messages_zh_TW.properties`
+- Modify: `ruoyi-admin/src/main/resources/i18n/messages_en_US.properties`
+- Modify: `ruoyi-admin/src/main/resources/i18n/messages_vi.properties`
+
+**Interfaces:**
+- Consumes: Task 1 DTOs.
+- Produces: `userOrders(Long userId,int page,int size)`.
+- Produces: `riderOrders(Long riderId,int page,int size,String tab,BigDecimal longitude,BigDecimal latitude)`.
+- Produces: `riderDetail(Long riderId,Long orderId)` returning `FlashDeliveryOrderDetailView`, never `Object`.
+
+- [ ] **Step 1: Write failing service tests**
+
+```java
+var userPage = fixture.service.userOrders(7L, 1, 10);
+var newTasks = fixture.service.riderOrders(8L, 1, 10, "newTask",
+        new BigDecimal("121.5"), new BigDecimal("25.0"));
+assertEquals("台北市中山區南京東路二段 100 號",
+        newTasks.getRecords().get(0).getPickupAddress());
+assertNull(fixture.service.riderDetail(8L, 10L).getPickup().getPhone());
+verify(fixture.logMapper, never()).selectList(any());
+```
+
+Tests must also capture SQL segments for all five tab mappings, reject `refund`/unknown tabs, reject half/malformed coordinates, keep scheduled orders hidden before their start, restrict non-new tabs to `rider_id`, and verify direct photo arrays grouped by `SENDER/PICKUP/DELIVERY`.
+
+- [ ] **Step 2: Run service and controller tests and verify failure**
+
+```powershell
+mvn -pl ruoyi-admin -am -Dtest='FlashDeliveryApplicationServiceTest,FlashDeliveryControllerContractTest,FlashDeliveryOrderViewTest,FlashDeliveryRiderOrderListViewTest' -Dsurefire.failIfNoSpecifiedTests=false test
+```
+
+Expected: failure on old method signatures, routes, scene filtering and wrapped detail response.
+
+- [ ] **Step 3: Implement controllers and query mapping**
+
+```java
+@GetMapping("/orders")
+public AjaxResult orders(@RequestHeader String token,
+        @RequestParam(defaultValue = "1") int page,
+        @RequestParam(defaultValue = "10") int size,
+        @RequestParam(defaultValue = "newTask") String tab,
+        @RequestParam(required = false) BigDecimal longitude,
+        @RequestParam(required = false) BigDecimal latitude) {
+    return success(service.riderOrders(userId(token), page, size, tab, longitude, latitude));
+}
+```
+
+User Controller uses only `page,size`. Service maps `newTask/toPickup/delivering/completed/cancelled` before `selectPage`; `newTask` applies `WAITING_ACCEPTANCE`、`rider_id IS NULL`、预约开始时间条件 and, when coordinates exist, the same `sys_qs_newtask_distance` radius and distance sorting used by `PosOrderQsOprateController.orderList`.
+
+- [ ] **Step 4: Implement list mapping and direct detail**
+
+```java
+private FlashDeliveryOrderDetailView participantDetail(FlashDeliveryOrder order,
+        boolean userView, boolean protectedRiderView) {
+    FlashDeliveryOrderDetailView view = detailOrderView(order, !protectedRiderView);
+    if (!protectedRiderView) groupImageUrls(view, selectImages(order.getId()));
+    if (userView) {
+        view.setDeliveryPinCode(Boolean.TRUE.equals(order.getPinRequired())
+                ? order.getDeliveryPinCode() : null);
+        view.setRider(riderSummary(order));
+    }
+    return view;
+}
+```
+
+Do not query `FlashDeliveryOrderLogMapper` while building App details. Pre-accept address views copy `city,area,handoffMethod,address,addressDetail` only; assigned rider/user detail additionally copies contact and exact coordinates. `newTask` page summary uses filtered page total as `nearbyTaskCount` and a same-condition maximum amount query as `highestOrderAmount`.
+
+- [ ] **Step 5: Add localized parameter errors and run targeted tests**
+
+Add `flash.delivery.tab.invalid` and `flash.delivery.coordinates.invalid` to all five message bundles, then run:
+
+```powershell
+mvn -pl ruoyi-admin -am -Dtest='FlashDeliveryApplicationServiceTest,FlashDeliveryControllerContractTest,FlashDeliveryOrderViewTest,FlashDeliveryRiderOrderListViewTest' -Dsurefire.failIfNoSpecifiedTests=false test
+```
+
+Expected: PASS.
+
+### Task 3: 更新契约文档并统一验证
+
+**Files:**
+- Modify: `docs/flash-delivery-app-api.md`
+- Modify: `specs/024-flash-delivery/quickstart.md`
+- Modify: `specs/024-flash-delivery/tasks.md`
+
+**Interfaces:**
+- Consumes: the implemented Controller routes and DTO field names from Tasks 1–2.
+- Produces: App integration examples that exactly match production code.
+
+- [ ] **Step 1: Replace obsolete request and response examples**
+
+Document only:
+
+```text
+GET /system/flashDelivery/orders?page=1&size=10
+GET /system/flashDelivery/rider/orders?page=1&size=10&tab=newTask&longitude=121.5&latitude=25.0
+```
+
+Remove `/available`、`/mine`、`scene`、`serviceType` list filters, approximate coordinates, `{order,images,logs}` App wrappers and App raw log examples. Keep platform audit response unchanged.
+
+- [ ] **Step 2: Run all affected tests and package**
+
+```powershell
+$env:JAVA_HOME='C:\Users\qmj\.jdks\graalvm-jdk-21.0.7'
+$env:PATH="$env:JAVA_HOME\bin;$env:PATH"
+mvn -pl ruoyi-admin -am -Dtest='FlashDeliveryApplicationServiceTest,FlashDeliveryControllerContractTest,FlashDeliveryOrderViewTest,FlashDeliveryRiderOrderListViewTest,FlashDeliveryI18nContractTest' -Dsurefire.failIfNoSpecifiedTests=false test
+mvn -pl ruoyi-admin -am -DskipTests package
+git diff --check
+```
+
+Expected: all targeted tests pass, package succeeds and diff check is clean.
+
+- [ ] **Step 3: Audit scope and commit**
+
+```powershell
+git diff --name-only
+$flashFiles = @(
+  'ruoyi-admin/src/main/java/com/ruoyi/app/flashdelivery/controller/FlashDeliveryUserController.java',
+  'ruoyi-admin/src/main/java/com/ruoyi/app/flashdelivery/controller/FlashDeliveryRiderController.java',
+  'ruoyi-admin/src/main/java/com/ruoyi/app/flashdelivery/service/FlashDeliveryApplicationService.java',
+  'ruoyi-admin/src/main/java/com/ruoyi/app/flashdelivery/dto/FlashDeliveryUserOrderListView.java',
+  'ruoyi-admin/src/main/java/com/ruoyi/app/flashdelivery/dto/FlashDeliveryRiderOrderListView.java',
+  'ruoyi-admin/src/main/java/com/ruoyi/app/flashdelivery/dto/FlashDeliveryRiderOrderPageView.java',
+  'ruoyi-admin/src/main/java/com/ruoyi/app/flashdelivery/dto/FlashDeliveryOrderDetailView.java',
+  'ruoyi-admin/src/main/java/com/ruoyi/app/flashdelivery/dto/FlashDeliveryAvailableOrderView.java',
+  'ruoyi-admin/src/main/java/com/ruoyi/app/flashdelivery/dto/FlashDeliveryImageView.java',
+  'ruoyi-admin/src/main/java/com/ruoyi/app/flashdelivery/dto/FlashDeliveryLogView.java',
+  'ruoyi-admin/src/test/java/com/ruoyi/app/flashdelivery/controller/FlashDeliveryControllerContractTest.java',
+  'ruoyi-admin/src/test/java/com/ruoyi/app/flashdelivery/dto/FlashDeliveryAvailableOrderViewTest.java',
+  'ruoyi-admin/src/test/java/com/ruoyi/app/flashdelivery/dto/FlashDeliveryRiderOrderListViewTest.java',
+  'ruoyi-admin/src/test/java/com/ruoyi/app/flashdelivery/dto/FlashDeliveryOrderViewTest.java',
+  'ruoyi-admin/src/test/java/com/ruoyi/app/flashdelivery/service/FlashDeliveryApplicationServiceTest.java',
+  'ruoyi-admin/src/main/resources/i18n/messages.properties',
+  'ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties',
+  'ruoyi-admin/src/main/resources/i18n/messages_zh_TW.properties',
+  'ruoyi-admin/src/main/resources/i18n/messages_en_US.properties',
+  'ruoyi-admin/src/main/resources/i18n/messages_vi.properties',
+  'docs/flash-delivery-app-api.md',
+  'specs/024-flash-delivery/quickstart.md',
+  'specs/024-flash-delivery/tasks.md'
+)
+git add -- $flashFiles
+git diff --cached --check
+git diff --cached --name-only
+git commit -m "精简闪送 App 订单接口"
+git push origin test
+```
+
+The staged list must not contain `.claude/homunculus/observations.jsonl`、`.tmp/` or `docs/merchant-subaccount-api.md`.

+ 10 - 0
specs/024-flash-delivery/tasks.md

@@ -76,3 +76,13 @@
 - [x] T045 在 `updatesql/sql.md` 追加开发阶段重建脚本:删除旧闪送测试表并创建运价锁、时段配置、新订单快照与索引的最终结构;只记录不执行
 - [x] T046 使用 JDK 21 运行后端定向测试和模块构建,运行前端定向测试、强制 ESLint、生产构建、CRLF 与两个仓库差异检查
 - [x] T047 核对两个仓库暂存范围,分别使用中文提交并推送当前 `test` 分支,不包含后端仓库原有脏文件
+
+## Phase 11:App 订单列表与详情精简
+
+- [ ] T048 先改 Controller 反射、列表字段白名单和详情直接响应测试,确认旧 `/available`、`/mine`、多筛选参数及 `{order,images,logs}` 契约红灯
+- [ ] T049 新增用户列表、骑手列表、骑手分页 DTO,将 App 详情 DTO 改为直接订单字段和三类明确照片 URL 数组,删除旧待抢/图片/日志 App DTO
+- [ ] T050 先改应用服务测试,覆盖用户轻量列表、五个骑手页签、外卖同规则附近范围/排序、摘要、预约条件、本人边界、接单前地址权限和固定详情结构并确认红灯
+- [ ] T051 将用户列表收敛为 `page,size`,将骑手 `/orders` 收敛为 `page,size,tab,longitude,latitude`,在数据库分页前完成条件与距离排序
+- [ ] T052 重写 App 详情映射,直接返回订单字段并按类型聚合照片 URL,不查询或返回原始状态日志;补齐五语言参数错误
+- [ ] T053 更新 `docs/flash-delivery-app-api.md` 与 quickstart,删除旧列表路由、筛选、近似坐标及 App 包装响应说明
+- [ ] T054 使用 JDK 21 运行闪送定向测试、i18n 契约、模块构建和差异检查,核对暂存范围后使用中文提交并推送 `test`