From f239bb739b91c755f3d8fbd638a172c36be08fe1 Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Sat, 8 Aug 2026 20:39:49 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../openapi/truck-appointments-v1.yaml | 49 + ...ruckAppointmentControllerContractTest.java | 10 +- ...in-test-env-acceptance-20260808123832.json | 401 +++++ ...in-test-env-acceptance-20260808123844.json | 937 ++++++++++++ ...se-service-center-postdeploy-20260808.json | 1287 +++++++++++++++++ .../truck-appointments.mjs | 107 +- 6 files changed, 2767 insertions(+), 24 deletions(-) create mode 100644 firstleg/src/main/resources/openapi/truck-appointments-v1.yaml create mode 100644 reports/admin-test-env-acceptance-20260808123832.json create mode 100644 reports/admin-test-env-acceptance-20260808123844.json create mode 100644 reports/admin-warehouse-service-center-postdeploy-20260808.json diff --git a/firstleg/src/main/resources/openapi/truck-appointments-v1.yaml b/firstleg/src/main/resources/openapi/truck-appointments-v1.yaml new file mode 100644 index 000000000..e005a4257 --- /dev/null +++ b/firstleg/src/main/resources/openapi/truck-appointments-v1.yaml @@ -0,0 +1,49 @@ +openapi: 3.0.3 +info: + title: Truck Appointment Attachments and History API + version: 1.0.0 +paths: + /api/platform/v1/truck-appointments/{id}/history: + parameters: [{$ref: '#/components/parameters/AppointmentId'}] + get: + summary: Query immutable appointment status history + responses: + '200': {description: History entries including action, from/to status, operator, reason and time} + /api/platform/v1/truck-appointments/{id}/attachments: + parameters: [{$ref: '#/components/parameters/AppointmentId'}] + get: + summary: Query attachment references owned by the appointment + responses: + '200': {description: Attachment references} + post: + summary: Reference a file already owned by the appointment customer and business scope + responses: + '200': {description: Created attachment reference} + /api/platform/v1/truck-appointments/{id}/attachments/upload: + parameters: [{$ref: '#/components/parameters/AppointmentId'}] + post: + summary: Upload and reference a truck appointment attachment + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + required: [file] + properties: + attachmentType: {type: string, maxLength: 32} + file: {type: string, format: binary} + responses: + '200': {description: Uploaded attachment reference} + /api/platform/v1/truck-appointments/{id}/attachments/{attachmentId}: + parameters: + - {$ref: '#/components/parameters/AppointmentId'} + - {$ref: '#/components/parameters/AttachmentId'} + delete: + summary: Delete an attachment reference owned by the appointment + responses: + '200': {description: Reference deleted} +components: + parameters: + AppointmentId: {name: id, in: path, required: true, schema: {type: string, pattern: '^[1-9][0-9]*$'}} + AttachmentId: {name: attachmentId, in: path, required: true, schema: {type: string, pattern: '^[1-9][0-9]*$'}} diff --git a/firstleg/src/test/java/com/baiyue/firstleg/controller/TruckAppointmentControllerContractTest.java b/firstleg/src/test/java/com/baiyue/firstleg/controller/TruckAppointmentControllerContractTest.java index 0ce0c6f5e..ad2540cb5 100644 --- a/firstleg/src/test/java/com/baiyue/firstleg/controller/TruckAppointmentControllerContractTest.java +++ b/firstleg/src/test/java/com/baiyue/firstleg/controller/TruckAppointmentControllerContractTest.java @@ -16,10 +16,16 @@ import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; class TruckAppointmentControllerContractTest { - @Test void exposesDedicatedEndpointAndPermissions() {String p=PlatformTruckAppointmentController.class.getAnnotation(org.springframework.web.bind.annotation.RequestMapping.class).value()[0];assertThat(p).isEqualTo("/api/platform/v1/truck-appointments"); for(String n:new String[]{"page","detail","create","edit","action","reschedule"}) assertThat(java.util.Arrays.stream(PlatformTruckAppointmentController.class.getDeclaredMethods()).anyMatch(m->m.getName().equals(n))).isTrue();} + @Test void exposesDedicatedEndpointAndPermissions() {String p=PlatformTruckAppointmentController.class.getAnnotation(org.springframework.web.bind.annotation.RequestMapping.class).value()[0];assertThat(p).isEqualTo("/api/platform/v1/truck-appointments"); for(String n:new String[]{"page","detail","history","attachments","attach","upload","deleteAttachment","create","edit","action","reschedule"}) assertThat(java.util.Arrays.stream(PlatformTruckAppointmentController.class.getDeclaredMethods()).anyMatch(m->m.getName().equals(n))).isTrue();} @Test void schemaHasAggregateTablesAndStates() throws Exception {String s=new ClassPathResource("db/phase3-truck-appointment-schema.sql").getContentAsString(StandardCharsets.UTF_8);assertThat(s).contains("fl_truck_appointment","fl_truck_appointment_history","fl_truck_appointment_attachment","fl_truck_appointment_operation","PENDING_DISPATCH","PICKUP_IN_PROGRESS","ARRIVED_WAREHOUSE","RESCHEDULED");} @Test void methodsHavePlatformPermissionsAndAuthenticatedScope() { - Map expected=Map.of("page","platform:firstleg:truck-appointment:list","detail","platform:firstleg:truck-appointment:view","create","platform:firstleg:truck-appointment:create","edit","platform:firstleg:truck-appointment:edit","action","platform:firstleg:truck-appointment:operate","reschedule","platform:firstleg:truck-appointment:operate"); + Map expected=Map.ofEntries( + Map.entry("page","platform:firstleg:truck-appointment:list"), Map.entry("detail","platform:firstleg:truck-appointment:view"), + Map.entry("history","platform:firstleg:truck-appointment:view"), Map.entry("attachments","platform:firstleg:truck-appointment:view"), + Map.entry("attach","platform:firstleg:truck-appointment:edit"), Map.entry("upload","platform:firstleg:truck-appointment:edit"), + Map.entry("deleteAttachment","platform:firstleg:truck-appointment:edit"), Map.entry("create","platform:firstleg:truck-appointment:create"), + Map.entry("edit","platform:firstleg:truck-appointment:edit"), Map.entry("action","platform:firstleg:truck-appointment:operate"), + Map.entry("reschedule","platform:firstleg:truck-appointment:operate")); for (Method m: PlatformTruckAppointmentController.class.getDeclaredMethods()) { if (!expected.containsKey(m.getName())) continue; assertThat(m.getAnnotation(PreAuthorize.class).value()).isEqualTo("hasAuthority('"+expected.get(m.getName())+"')"); assertThat(java.util.Arrays.stream(m.getParameterAnnotations()).anyMatch(a -> java.util.Arrays.stream(a).anyMatch(x -> x.annotationType()==AuthenticationPrincipal.class))).isTrue(); } } @Test void actionKeepsOptionalIdempotencyHeaders() throws Exception { diff --git a/reports/admin-test-env-acceptance-20260808123832.json b/reports/admin-test-env-acceptance-20260808123832.json new file mode 100644 index 000000000..837d3d1fc --- /dev/null +++ b/reports/admin-test-env-acceptance-20260808123832.json @@ -0,0 +1,401 @@ +{ + "reportName": "后台管理测试环境 HTTP API 验收", + "marker": "ADMIN-API-20260808123832880", + "gateway": "http://8.163.30.128:9000", + "generatedAt": "2026-08-08T12:38:35.384Z", + "startedAt": "2026-08-08T12:38:32.880Z", + "success": true, + "fatal": null, + "summary": { + "total": 19, + "passed": 19, + "failed": 0 + }, + "modules": [ + { + "name": "supplemental-boundaries", + "startedAt": "2026-08-08T12:38:33.252Z", + "finishedAt": "2026-08-08T12:38:35.384Z", + "success": true, + "passed": 18, + "failed": 0, + "fatal": null + } + ], + "scenarios": [ + { + "name": "admin-boundary-automation", + "module": "supplemental-boundaries", + "success": true, + "deploymentBlocked": false, + "passed": 18, + "failed": 0 + } + ], + "deploymentBlockers": [], + "coverageGaps": [ + { + "module": "supplemental-boundaries", + "scenario": "resource-occupancy", + "name": "托盘/库位真实占用删除保护", + "reason": "当前公共验收 API 未提供可安全构造并释放占用关联的独立 fixture;未操作历史资源", + "category": "no-public-fixture-api" + } + ], + "createdResources": {}, + "excluded": [ + { + "scope": "dashboard", + "reason": "首页为静态演示数据,不调用后端 API" + }, + { + "scope": "hidden-prototypes", + "reason": "隐藏原型页面尚无已确认后端契约" + } + ], + "securityNote": "报告不保存登录密码、Access Token、Refresh Token、图片二进制或 OCR 原文全文。", + "steps": [ + { + "module": "authentication", + "scenario": null, + "name": "平台管理员登录", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/auth/login" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "7a4122c2-57cb-43a1-8f6c-8a0e0e001e08, 0e20722a-b785-40dd-8abd-e49b1b4bb541", + "traceId": "ca5a6a7db86f4c449f755bb3a906ef00", + "evidence": "", + "checkedAt": "2026-08-08T12:38:33.250Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "admin-boundary-automation", + "name": "创建边界验收隔离仓库", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/warehouse-admin" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "68acea99-d807-4dfc-9f5e-ae7d4cd6537c, 3ab9ad21-b100-48b2-8fff-361fc59dd229", + "traceId": "e779ee6717044b50bcf2a680ddd65b78", + "evidence": "", + "checkedAt": "2026-08-08T12:38:33.978Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "admin-boundary-automation", + "name": "创建边界验收隔离库位", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/locations?tenantId=0" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "50858329-b85d-4dfd-bb29-0740f5101567, 6754a5b0-2725-4ece-abac-72e394a827d5", + "traceId": "0d4cc4498ba14702a10892279f10b507", + "evidence": "", + "checkedAt": "2026-08-08T12:38:34.095Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "admin-boundary-automation", + "name": "读取隔离库位版本", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/locations/2086069551981707265?tenantId=0&warehouseId=2086069551419670529" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "ec2e456d-660f-4368-86ea-6ea509c1591c, 5a6b624c-7db7-41a1-a985-9427c6441465", + "traceId": "eb59590f77724d9183cfea4d261e60e4", + "evidence": "", + "checkedAt": "2026-08-08T12:38:34.140Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "admin-boundary-automation", + "name": "更新隔离库位以推进版本", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "PUT", + "path": "/api/platform/v1/locations/2086069551981707265?tenantId=0&warehouseId=2086069551419670529" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "faaddf3b-9280-490e-b424-68b48065d0d2, 7c81a029-31ce-4749-b51b-86d52ab8e518", + "traceId": "7885cc13944140c78f01ffc9ed830a30", + "evidence": "version=0", + "checkedAt": "2026-08-08T12:38:34.214Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "admin-boundary-automation", + "name": "库位旧 version PUT 返回冲突", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "PUT", + "path": "/api/platform/v1/locations/2086069551981707265?tenantId=0&warehouseId=2086069551419670529" + }, + "http": 200, + "code": "A0409", + "message": "库位已被其他操作修改,请刷新后重试", + "requestId": "c61bfeaf-c6d7-45b1-a819-149fccfc449b", + "traceId": "98cd3bf54e074a4eafff545932927d5a", + "evidence": "HTTP=200, code=A0409", + "checkedAt": "2026-08-08T12:38:34.271Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "admin-boundary-automation", + "name": "冲突后回查库位", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/locations/2086069551981707265?tenantId=0&warehouseId=2086069551419670529" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "5daeea9d-1de6-49d9-af81-08c3cfe900ed, 08eb3a73-7dc6-4306-8880-6acd628f9439", + "traceId": "24bf5b3f0fd243d1a3955e42370dd718", + "evidence": "", + "checkedAt": "2026-08-08T12:38:34.314Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "admin-boundary-automation", + "name": "库位冲突未造成部分更新", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/locations/2086069551981707265?tenantId=0&warehouseId=2086069551419670529" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "5daeea9d-1de6-49d9-af81-08c3cfe900ed, 08eb3a73-7dc6-4306-8880-6acd628f9439", + "traceId": "24bf5b3f0fd243d1a3955e42370dd718", + "evidence": "name=边界库位-编辑", + "checkedAt": "2026-08-08T12:38:34.314Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "import-boundaries", + "name": "仓库空文件安全失败且不模拟导入成功", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/warehouse-admin/import?tenantId=0&dryRun=true" + }, + "http": 200, + "code": "A0422", + "message": "仓库导入文件校验失败", + "requestId": "2e8ad0c6-c08f-410e-8892-471ef98094b7", + "traceId": "1301488310ef422294f5f3522eb9ee92", + "evidence": "HTTP=200, code=A0422, bytes=0", + "checkedAt": "2026-08-08T12:38:34.365Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "import-boundaries", + "name": "仓库缺列伪 XLSX安全失败且不模拟导入成功", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/warehouse-admin/import?tenantId=0&dryRun=true" + }, + "http": 200, + "code": "A0422", + "message": "仓库导入文件校验失败", + "requestId": "310528eb-14e9-4a13-a9cd-a448b749e550", + "traceId": "bfed5d5245de4d11991d66b2d4eb2e91", + "evidence": "HTTP=200, code=A0422, bytes=6", + "checkedAt": "2026-08-08T12:38:34.495Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "import-boundaries", + "name": "快递公司错误扩展名安全失败且不模拟导入成功", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/express-companies/import?tenantId=0" + }, + "http": 200, + "code": "A0422", + "message": "快递公司导入文件校验失败", + "requestId": "66f6c744-a075-40dd-9433-aca813ff1ae0", + "traceId": "544a7ebdc4954baf8e678c684f7421fc", + "evidence": "HTTP=200, code=A0422, bytes=27", + "checkedAt": "2026-08-08T12:38:34.539Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "import-boundaries", + "name": "往来单位非 XLSX安全失败且不模拟导入成功", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/partners/import?tenantId=0" + }, + "http": 200, + "code": "A0422", + "message": "往来单位导入文件校验失败", + "requestId": "f17bb5a5-f47e-4551-a007-e427e7d4b018", + "traceId": "a81168d94dde4eee89bd3fce348f3c91", + "evidence": "HTTP=200, code=A0422, bytes=27", + "checkedAt": "2026-08-08T12:38:34.582Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "admin-boundary-automation", + "name": "错误客户海外仓费用 ID 安全失败", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/iam/tenants/999999999999999999/overseas-storage-fees" + }, + "http": 200, + "code": "A0404", + "message": "海外仓费用不存在", + "requestId": "93257eb1-50e1-465b-8c60-a91839406f7c", + "traceId": "4f867f925be844308c4ac133fb14232a", + "evidence": "HTTP=200, code=A0404", + "checkedAt": "2026-08-08T12:38:34.678Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "admin-boundary-automation", + "name": "库位列表未授权边界响应正确", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/locations?page=1&size=1&tenantId=0" + }, + "http": 401, + "code": "A0401", + "message": "未登录或令牌已失效", + "requestId": "09a9dbb3-2492", + "traceId": null, + "evidence": "HTTP=401, code=A0401", + "checkedAt": "2026-08-08T12:38:34.702Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "admin-boundary-automation", + "name": "下载中心非法页码边界响应正确", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/files/export-tasks?page=0&size=1" + }, + "http": 200, + "code": "A0422", + "message": "page.page: must be greater than or equal to 1", + "requestId": "a424cdde-4050-4646-9629-73d9033232e6", + "traceId": "a807d130122c41fea37d6fdf77b6b319", + "evidence": "HTTP=200, code=A0422", + "checkedAt": "2026-08-08T12:38:35.009Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "admin-boundary-automation", + "name": "船期价格非法状态边界响应正确", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/fba-pricing/carrier-rates/price-books?status=INVALID" + }, + "http": 200, + "code": "A0400", + "message": "Bad request", + "requestId": "f6f27fe9-fe8d-40a8-8533-3839a10dd9ea", + "traceId": "543a3eb50f6040dd9db2ccd621634ff9", + "evidence": "HTTP=200, code=A0400", + "checkedAt": "2026-08-08T12:38:35.235Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "admin-boundary-automation", + "name": "停用隔离库位以便清理", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "PATCH", + "path": "/api/platform/v1/locations/2086069551981707265/status?tenantId=0&warehouseId=2086069551419670529" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "b4db06df-896c-4cff-9a41-00fad82f1702, 3213100d-ef66-4484-8732-59406c57ef1e", + "traceId": "7f5423ff170849948dd98eb3d0047405", + "evidence": "", + "checkedAt": "2026-08-08T12:38:35.289Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "admin-boundary-automation", + "name": "删除隔离库位", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "DELETE", + "path": "/api/platform/v1/locations/2086069551981707265?tenantId=0&warehouseId=2086069551419670529&version=2" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "293e1cd9-56b5-41a1-9679-65d9568f301f, 718b10c4-2980-41d2-9095-0c9989b4b108", + "traceId": "470c23f5d6f84f32adfd5d5e43478af2", + "evidence": "", + "checkedAt": "2026-08-08T12:38:35.326Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "admin-boundary-automation", + "name": "停用隔离仓库", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "PATCH", + "path": "/api/platform/v1/warehouse-admin/2086069551419670529/status?tenantId=0&status=INACTIVE" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "f4aa5fb6-a1d8-4ce4-a9cb-ec8718a968c2, 46128fd3-7a3c-4c96-b3bb-0a11b375ed5b", + "traceId": "1e7e85e33f3f43db8e634ee6e5b8b3ab", + "evidence": "", + "checkedAt": "2026-08-08T12:38:35.384Z" + } + ] +} diff --git a/reports/admin-test-env-acceptance-20260808123844.json b/reports/admin-test-env-acceptance-20260808123844.json new file mode 100644 index 000000000..10c4162de --- /dev/null +++ b/reports/admin-test-env-acceptance-20260808123844.json @@ -0,0 +1,937 @@ +{ + "reportName": "后台管理测试环境 HTTP API 验收", + "marker": "ADMIN-API-20260808123844850", + "gateway": "http://8.163.30.128:9000", + "generatedAt": "2026-08-08T12:38:47.387Z", + "startedAt": "2026-08-08T12:38:44.850Z", + "success": false, + "fatal": null, + "summary": { + "total": 47, + "passed": 45, + "failed": 2 + }, + "modules": [ + { + "name": "ocean-bookings", + "startedAt": "2026-08-08T12:38:45.224Z", + "finishedAt": "2026-08-08T12:38:46.748Z", + "success": true, + "passed": 23, + "failed": 0, + "fatal": null + }, + { + "name": "truck-appointments", + "startedAt": "2026-08-08T12:38:46.748Z", + "finishedAt": "2026-08-08T12:38:47.226Z", + "success": false, + "passed": 13, + "failed": 2, + "fatal": null + }, + { + "name": "service-center-flow", + "startedAt": "2026-08-08T12:38:47.227Z", + "finishedAt": "2026-08-08T12:38:47.387Z", + "success": true, + "passed": 8, + "failed": 0, + "fatal": null + } + ], + "scenarios": [], + "deploymentBlockers": [ + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "创建隔离拖车预约", + "evidence": "", + "code": "A0400", + "requestId": "a0e77899-707f-423d-a194-b00e464a0b06", + "traceId": "ecd32424e4674136a3ab42dcd50f8d50" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约费用、司机车辆和地址字段完整", + "evidence": "id=missing, status=missing", + "code": "A0400", + "requestId": "a0e77899-707f-423d-a194-b00e464a0b06", + "traceId": "ecd32424e4674136a3ab42dcd50f8d50" + } + ], + "coverageGaps": [], + "createdResources": { + "oceanBooking": { + "id": "2086069601618669569", + "marker": "ADMIN-API-20260808123844850", + "finalStatus": "RELEASED" + }, + "serviceCenterFlow": { + "appointmentId": "2086069607310340098", + "oceanBookingId": "2086069601618669569", + "marker": "ADMIN-API-20260808123844850", + "finalStatus": "CANCELLED" + } + }, + "excluded": [ + { + "scope": "dashboard", + "reason": "首页为静态演示数据,不调用后端 API" + }, + { + "scope": "hidden-prototypes", + "reason": "隐藏原型页面尚无已确认后端契约" + } + ], + "securityNote": "报告不保存登录密码、Access Token、Refresh Token、图片二进制或 OCR 原文全文。", + "steps": [ + { + "module": "authentication", + "scenario": null, + "name": "平台管理员登录", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/auth/login" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "adf1a201-83b2-4dc7-a3c0-af89c51a1453, 05bc222c-53f5-4461-8750-79b99473b672", + "traceId": "6d8c7a0ca6ea4d188f45af50c3eb4b6d", + "evidence": "", + "checkedAt": "2026-08-08T12:38:45.223Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "订舱列表分页与 keyword 查询", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/ocean-bookings?page=1&size=5&keyword=ADMIN-API-20260808123844850" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "8282e144-2f40-4105-aa7e-e9003cc78103, 81f90a3b-096a-45a3-9f40-7e8235fb422a", + "traceId": "73a39258d4ad488b8ba6b3418145e321", + "evidence": "", + "checkedAt": "2026-08-08T12:38:45.485Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "订舱列表分页结构正确", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/ocean-bookings?page=1&size=5&keyword=ADMIN-API-20260808123844850" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "8282e144-2f40-4105-aa7e-e9003cc78103, 81f90a3b-096a-45a3-9f40-7e8235fb422a", + "traceId": "73a39258d4ad488b8ba6b3418145e321", + "evidence": "records=0", + "checkedAt": "2026-08-08T12:38:45.485Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "订舱 DRAFT 状态筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/ocean-bookings?page=1&size=5&status=DRAFT" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "ae93ca45-7680-4222-8c2b-5a7c28ae22b8, e4475ec5-257e-4520-82ce-c4fdf3595468", + "traceId": "71bc0cdf508e4044b8d2453ca9e96025", + "evidence": "HTTP=200, code=200, records=0", + "checkedAt": "2026-08-08T12:38:45.537Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "订舱 SUBMITTED 状态筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/ocean-bookings?page=1&size=5&status=SUBMITTED" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "2e2fc320-f075-48b2-8e7b-5fde389fcdd1, 9523048d-b9b1-43c5-ba7f-123d20e01e3c", + "traceId": "afde9ebbdb294e53bde0f88d4de40921", + "evidence": "HTTP=200, code=200, records=0", + "checkedAt": "2026-08-08T12:38:45.579Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "订舱 CONFIRMED 状态筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/ocean-bookings?page=1&size=5&status=CONFIRMED" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "ebc1bbb8-2d98-4211-a906-611c550d271f, 26e2776a-4862-40f0-a70b-df38efc7a7cb", + "traceId": "d146b43157f1481aa418e29237b8120c", + "evidence": "HTTP=200, code=200, records=0", + "checkedAt": "2026-08-08T12:38:45.628Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "订舱 RELEASED 状态筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/ocean-bookings?page=1&size=5&status=RELEASED" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "3a23ed1f-71bb-4ace-a5f0-c3f384e48ca4, 1a4d8ed9-1d12-4c90-be10-a42a730057de", + "traceId": "95eba836c1824e7394fa48f38cea6b01", + "evidence": "HTTP=200, code=200, records=5", + "checkedAt": "2026-08-08T12:38:45.687Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "订舱 FAILED 状态筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/ocean-bookings?page=1&size=5&status=FAILED" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "3f8e4af3-8d1f-4831-89b2-b49aef69f16a, a69b2cfe-9cdb-4849-94bc-6600ef68e979", + "traceId": "6b0a1599f2f743bdb30b919dc5dc2298", + "evidence": "HTTP=200, code=200, records=0", + "checkedAt": "2026-08-08T12:38:45.729Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "订舱 CANCELLED 状态筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/ocean-bookings?page=1&size=5&status=CANCELLED" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "b00224b6-4162-4e7f-91d4-540291c012c1, 75e2d97e-321b-419d-8bdf-5b60de1c7ace", + "traceId": "cd0f9f9208d943fba451f5f46e6d06fd", + "evidence": "HTTP=200, code=200, records=0", + "checkedAt": "2026-08-08T12:38:45.759Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "创建隔离海运订舱", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/ocean-bookings" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "125ba892-a866-41ae-a796-081dce3cc6f8, ec2b1999-5afa-4ae4-b628-4e1a5525be53", + "traceId": "2763a6b3d70346f8a0e57aa3043f9282", + "evidence": "key=ADMIN-API-20260808123844850-ocean-create", + "checkedAt": "2026-08-08T12:38:46.022Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "订舱 DTO 字段、DRAFT 和9类关联字段完整", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/ocean-bookings" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "125ba892-a866-41ae-a796-081dce3cc6f8, ec2b1999-5afa-4ae4-b628-4e1a5525be53", + "traceId": "2763a6b3d70346f8a0e57aa3043f9282", + "evidence": "bookingId=2086069601618669569, parties=3, requirements=1", + "checkedAt": "2026-08-08T12:38:46.022Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "创建 Idempotency-Key 重放返回同一订舱", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/ocean-bookings" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "959b4cb3-639e-477a-86e8-7eaeea5d8bf9, 7aff8266-91d8-478c-a170-fda9ed20602a", + "traceId": "b2fda443ccb14c0eb23a96e57f53c0c8", + "evidence": "first=2086069601618669569, replay=2086069601618669569", + "checkedAt": "2026-08-08T12:38:46.078Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "编辑 DRAFT 订舱", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "PUT", + "path": "/api/platform/v1/ocean-bookings/2086069601618669569" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "ef7163c3-e4d3-4b83-9504-417674273106, e289b155-f480-4bb0-8bd7-ddb2ed1fe461", + "traceId": "3621b9645a2f40e682b6e49e88018c8d", + "evidence": "version=0", + "checkedAt": "2026-08-08T12:38:46.189Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "订舱旧版本编辑返回冲突", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "PUT", + "path": "/api/platform/v1/ocean-bookings/2086069601618669569" + }, + "http": 200, + "code": "A0409", + "message": "数据已被其他人修改,请刷新后重试", + "requestId": "86fd3076-2ad0-4f0b-be45-5d3a23aa25c4", + "traceId": "4328fda9b3e4498ead9b15405b2416f1", + "evidence": "HTTP=200, code=A0409", + "checkedAt": "2026-08-08T12:38:46.228Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "冲突后回查订舱", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/ocean-bookings/2086069601618669569" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "c9a4e2ad-2bb8-4071-84fc-89d0b5b97f90, 985015d4-1f51-41e0-9370-66d0ec8a743a", + "traceId": "8c87a9161ba9444c843c17109b847ec0", + "evidence": "", + "checkedAt": "2026-08-08T12:38:46.291Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "订舱冲突未部分更新", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/ocean-bookings/2086069601618669569" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "c9a4e2ad-2bb8-4071-84fc-89d0b5b97f90, 985015d4-1f51-41e0-9370-66d0ec8a743a", + "traceId": "8c87a9161ba9444c843c17109b847ec0", + "evidence": "vessel=编辑船-8123844850", + "checkedAt": "2026-08-08T12:38:46.291Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "提交订舱", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/ocean-bookings/2086069601618669569/submit" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "19fec60a-5558-4c57-a38a-49f7e1eb282d, baaa7dba-5966-4a6b-b09b-d21446ba3104", + "traceId": "76470dd20b4c4d2380819bee2f7d624b", + "evidence": "status=SUBMITTED", + "checkedAt": "2026-08-08T12:38:46.385Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "确认订舱", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/ocean-bookings/2086069601618669569/confirm" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "9ce4a320-b4ae-4b5a-8787-484060de58d6, 808e9b04-23bb-4065-898f-9edd21242746", + "traceId": "2c9f92a164034e96afc6e8faec22d7f4", + "evidence": "status=CONFIRMED", + "checkedAt": "2026-08-08T12:38:46.469Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "申请改船", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/ocean-bookings/2086069601618669569/change-request" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "841ce97b-0d54-4aa9-bfba-2276f1dff274, 59734c0f-527e-4eaa-9b15-33b6283425e6", + "traceId": "33af20c208a843809c6367a6b8954385", + "evidence": "", + "checkedAt": "2026-08-08T12:38:46.553Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "确认改船", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/ocean-bookings/2086069601618669569/change-confirm" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "68dea18b-9300-41cb-9db6-48d827b8e36d, b7e9421a-1510-4bbe-9cb8-bdc3d1b90683", + "traceId": "10974d14aa6e45728f04d91a5edfc716", + "evidence": "status=CONFIRMED", + "checkedAt": "2026-08-08T12:38:46.620Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "放舱", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/ocean-bookings/2086069601618669569/release" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "04922d43-7ac1-4278-ae52-8b4237f05b77, c56cd9ea-cbba-49a0-b559-263a1cf4392f", + "traceId": "c39f3a4afefc45d597056c8dd678d85f", + "evidence": "status=RELEASED", + "checkedAt": "2026-08-08T12:38:46.682Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "回查 RELEASED 订舱详情", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/ocean-bookings/2086069601618669569" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "3163e816-f73a-43f7-9414-c29cf1d2dbaf, d19e4a7e-66b9-43cd-b429-af1467b32b39", + "traceId": "138f19b8c06e4d9bb1d78c53d555431f", + "evidence": "", + "checkedAt": "2026-08-08T12:38:46.712Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "订舱状态历史、审计操作者和终态完整", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/ocean-bookings/2086069601618669569" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "3163e816-f73a-43f7-9414-c29cf1d2dbaf, d19e4a7e-66b9-43cd-b429-af1467b32b39", + "traceId": "138f19b8c06e4d9bb1d78c53d555431f", + "evidence": "status=RELEASED, histories=6", + "checkedAt": "2026-08-08T12:38:46.712Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "不存在订舱详情安全失败", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/ocean-bookings/999999999999999999" + }, + "http": 200, + "code": "A0404", + "message": "订舱单不存在", + "requestId": "aec2d889-358d-42d8-8bc1-6ef038fde9d1", + "traceId": "82359864e1244961b9da53906e891235", + "evidence": "HTTP=200, code=A0404", + "checkedAt": "2026-08-08T12:38:46.747Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约分页 keyword 查询", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments?page=1&size=5&keyword=ADMIN-API-20260808123844850" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "f1bfff8d-c263-4bc5-adcb-581bcf52d966, 9c310982-c9b1-4c2d-b251-efe55caf3ac3", + "traceId": "ddc9dac485f44e4b99e687bca1390818", + "evidence": "", + "checkedAt": "2026-08-08T12:38:46.786Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约分页结构正确", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments?page=1&size=5&keyword=ADMIN-API-20260808123844850" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "f1bfff8d-c263-4bc5-adcb-581bcf52d966, 9c310982-c9b1-4c2d-b251-efe55caf3ac3", + "traceId": "ddc9dac485f44e4b99e687bca1390818", + "evidence": "records=0", + "checkedAt": "2026-08-08T12:38:46.786Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约 DRAFT 筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments?page=1&size=5&status=DRAFT" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "85c54ebe-8741-4d2f-a6bb-cc2b8a9d0bcb, d772c85c-1042-4965-bb00-7ce17271b4a7", + "traceId": "874e8298000e4e8b8632064e6c7e87d3", + "evidence": "HTTP=200, code=200, records=0", + "checkedAt": "2026-08-08T12:38:46.829Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约 PENDING_DISPATCH 筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments?page=1&size=5&status=PENDING_DISPATCH" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "414c386b-09f7-47e7-911f-262564f9b1cb, 86bcc25a-1a1c-47f8-91d4-9cfdf8fbee22", + "traceId": "4a82fa02255149cf8db6422a99b1f068", + "evidence": "HTTP=200, code=200, records=0", + "checkedAt": "2026-08-08T12:38:46.853Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约 DISPATCHED 筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments?page=1&size=5&status=DISPATCHED" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "8a8163d5-cc3d-4364-afc2-8a47f871cf88, 652a9de8-9bec-4239-9413-10e6ff1bfaed", + "traceId": "c2fe6be757f74669bd97041d0b2b64c2", + "evidence": "HTTP=200, code=200, records=0", + "checkedAt": "2026-08-08T12:38:46.889Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约 PICKUP_IN_PROGRESS 筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments?page=1&size=5&status=PICKUP_IN_PROGRESS" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "5f96c4f2-9439-42ce-af06-5da1eac4551a, 5ebb8e5f-47f2-4c1d-b437-2e8c0c6f8542", + "traceId": "c14b59053dff44319aedd657e2d1fb32", + "evidence": "HTTP=200, code=200, records=0", + "checkedAt": "2026-08-08T12:38:46.916Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约 ARRIVED_WAREHOUSE 筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments?page=1&size=5&status=ARRIVED_WAREHOUSE" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "eab4ebd3-c797-4d89-aa7d-2e67b1c12164, 70869095-f565-40cf-9d90-44d9243e7ddf", + "traceId": "73d0d50cd021455da9dc9ce6e5e7154b", + "evidence": "HTTP=200, code=200, records=0", + "checkedAt": "2026-08-08T12:38:46.947Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约 LOADING 筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments?page=1&size=5&status=LOADING" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "62d80194-2812-4ec2-b417-881fe7816868, 52f240d5-c553-4283-a0a6-501474c078e6", + "traceId": "81d3eb25c7da40a5b0db6c705a9968bf", + "evidence": "HTTP=200, code=200, records=0", + "checkedAt": "2026-08-08T12:38:46.978Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约 DEPARTED 筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments?page=1&size=5&status=DEPARTED" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "382928a0-7ba0-422e-a154-58a5dabc5446, 950b0112-ad6a-4e6f-9e53-579ccfb28c7e", + "traceId": "4feeb921516547c8a2f646e082535053", + "evidence": "HTTP=200, code=200, records=0", + "checkedAt": "2026-08-08T12:38:47.011Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约 COMPLETED 筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments?page=1&size=5&status=COMPLETED" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "146427b7-62cc-4729-9fd0-be22bc65c9c7, e1fe483a-6f93-4d85-b437-bf4415dc3b22", + "traceId": "b4dc9c5f033846549ae6bb604e4fbebf", + "evidence": "HTTP=200, code=200, records=5", + "checkedAt": "2026-08-08T12:38:47.052Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约 RESCHEDULED 筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments?page=1&size=5&status=RESCHEDULED" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "ab12d760-8be1-42f9-a6ae-ca15cf9729c7, 3ec600b6-9ce1-4b1a-98dd-22c57de1fcc4", + "traceId": "570d0bb7986e4af58fa65bde23777604", + "evidence": "HTTP=200, code=200, records=0", + "checkedAt": "2026-08-08T12:38:47.088Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约 EXCEPTION 筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments?page=1&size=5&status=EXCEPTION" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "969dbebe-5c56-45b1-b7c9-32925e488071, 6068d2b3-9285-455d-a6fc-faca766a50ac", + "traceId": "0ce51b860c754b1ca57d8ef14800a60d", + "evidence": "HTTP=200, code=200, records=0", + "checkedAt": "2026-08-08T12:38:47.119Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约 CANCELLED 筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments?page=1&size=5&status=CANCELLED" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "535be6c9-1eae-4a49-8436-de9b24bcc6f2, 8ade76ff-5814-44f6-b29c-9bfffe8dbd7b", + "traceId": "bfc3ab1892634acabfff0ae702b39fa9", + "evidence": "HTTP=200, code=200, records=4", + "checkedAt": "2026-08-08T12:38:47.155Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "创建隔离拖车预约", + "passed": false, + "deploymentBlocker": true, + "request": { + "method": "POST", + "path": "/api/platform/v1/truck-appointments" + }, + "http": 200, + "code": "A0400", + "message": "oceanBookingId不能为空", + "requestId": "a0e77899-707f-423d-a194-b00e464a0b06", + "traceId": "ecd32424e4674136a3ab42dcd50f8d50", + "evidence": "", + "checkedAt": "2026-08-08T12:38:47.226Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约费用、司机车辆和地址字段完整", + "passed": false, + "deploymentBlocker": true, + "request": { + "method": "POST", + "path": "/api/platform/v1/truck-appointments" + }, + "http": 200, + "code": "A0400", + "message": "oceanBookingId不能为空", + "requestId": "a0e77899-707f-423d-a194-b00e464a0b06", + "traceId": "ecd32424e4674136a3ab42dcd50f8d50", + "evidence": "id=missing, status=missing", + "checkedAt": "2026-08-08T12:38:47.226Z" + }, + { + "module": "service-center-flow", + "scenario": "service-center-cross-flow", + "name": "创建关联海运订舱的拖车预约", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/truck-appointments" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "d79b07fd-ae0b-4d3b-b6c5-af4cf9f290c7, c0961ea6-1932-492f-a6d3-ef80c7e0f5c3", + "traceId": "b6b5b2cf0ed24100a6c2c7ffb594e037", + "evidence": "oceanBookingId=2086069601618669569", + "checkedAt": "2026-08-08T12:38:47.277Z" + }, + { + "module": "service-center-flow", + "scenario": "service-center-cross-flow", + "name": "拖车预约关联订舱 ID、版本和审计字段完整", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/truck-appointments" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "d79b07fd-ae0b-4d3b-b6c5-af4cf9f290c7, c0961ea6-1932-492f-a6d3-ef80c7e0f5c3", + "traceId": "b6b5b2cf0ed24100a6c2c7ffb594e037", + "evidence": "appointmentId=2086069607310340098, oceanBookingId=2086069601618669569, version=0", + "checkedAt": "2026-08-08T12:38:47.277Z" + }, + { + "module": "service-center-flow", + "scenario": "service-center-cross-flow", + "name": "取消跨服务链路拖车预约", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/truck-appointments/2086069607310340098/cancel" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "add9beb1-33a4-43e3-a393-805e61e8a9ca, d1b4cd84-59a5-4f1f-bcc2-8b9bdf405b14", + "traceId": "cc24e6133d9f48d5a5f003fcb14e1d7f", + "evidence": "", + "checkedAt": "2026-08-08T12:38:47.320Z" + }, + { + "module": "service-center-flow", + "scenario": "service-center-cross-flow", + "name": "跨服务链路安全终态为 CANCELLED", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/truck-appointments/2086069607310340098/cancel" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "add9beb1-33a4-43e3-a393-805e61e8a9ca, d1b4cd84-59a5-4f1f-bcc2-8b9bdf405b14", + "traceId": "cc24e6133d9f48d5a5f003fcb14e1d7f", + "evidence": "status=CANCELLED", + "checkedAt": "2026-08-08T12:38:47.320Z" + }, + { + "module": "service-center-flow", + "scenario": "service-center-cross-flow", + "name": "回查跨服务链路安全终态", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments/2086069607310340098" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "ef742f81-bb2d-4c6f-aca6-2aa1cd0b34b8, 2d10218c-aacc-45fd-9bf2-bed5c586c6e1", + "traceId": "1fc1dd79f62a4c5c900003ac7388b1d1", + "evidence": "", + "checkedAt": "2026-08-08T12:38:47.354Z" + }, + { + "module": "service-center-flow", + "scenario": "service-center-cross-flow", + "name": "跨服务链路终态持久化且关联订舱未漂移", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments/2086069607310340098" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "ef742f81-bb2d-4c6f-aca6-2aa1cd0b34b8, 2d10218c-aacc-45fd-9bf2-bed5c586c6e1", + "traceId": "1fc1dd79f62a4c5c900003ac7388b1d1", + "evidence": "status=CANCELLED, oceanBookingId=2086069601618669569", + "checkedAt": "2026-08-08T12:38:47.354Z" + }, + { + "module": "service-center-flow", + "scenario": "service-center-cross-flow", + "name": "查询跨服务链路拖车预约状态历史", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments/2086069607310340098/history" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "46532c3d-a62b-4532-9261-9908bc8f017f, 42e8644e-0c46-4a36-96aa-4818bb48bcfe", + "traceId": "553bf4e56b964ef9bacaa745956f9c6e", + "evidence": "", + "checkedAt": "2026-08-08T12:38:47.387Z" + }, + { + "module": "service-center-flow", + "scenario": "service-center-cross-flow", + "name": "跨服务链路历史包含归属、状态、操作者、时间和备注", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments/2086069607310340098/history" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "46532c3d-a62b-4532-9261-9908bc8f017f, 42e8644e-0c46-4a36-96aa-4818bb48bcfe", + "traceId": "553bf4e56b964ef9bacaa745956f9c6e", + "evidence": "history=2, cancelFrom=DRAFT, cancelTo=CANCELLED", + "checkedAt": "2026-08-08T12:38:47.387Z" + } + ] +} diff --git a/reports/admin-warehouse-service-center-postdeploy-20260808.json b/reports/admin-warehouse-service-center-postdeploy-20260808.json new file mode 100644 index 000000000..2329223aa --- /dev/null +++ b/reports/admin-warehouse-service-center-postdeploy-20260808.json @@ -0,0 +1,1287 @@ +{ + "reportName": "后台管理测试环境 HTTP API 验收", + "marker": "ADMIN-API-20260808123912960", + "gateway": "http://8.163.30.128:9000", + "generatedAt": "2026-08-08T12:39:15.288Z", + "startedAt": "2026-08-08T12:39:12.960Z", + "success": false, + "fatal": null, + "summary": { + "total": 65, + "passed": 63, + "failed": 2 + }, + "modules": [ + { + "name": "supplemental-boundaries", + "startedAt": "2026-08-08T12:39:13.334Z", + "finishedAt": "2026-08-08T12:39:13.942Z", + "success": true, + "passed": 18, + "failed": 0, + "fatal": null + }, + { + "name": "ocean-bookings", + "startedAt": "2026-08-08T12:39:13.943Z", + "finishedAt": "2026-08-08T12:39:14.746Z", + "success": true, + "passed": 23, + "failed": 0, + "fatal": null + }, + { + "name": "truck-appointments", + "startedAt": "2026-08-08T12:39:14.747Z", + "finishedAt": "2026-08-08T12:39:15.161Z", + "success": false, + "passed": 13, + "failed": 2, + "fatal": null + }, + { + "name": "service-center-flow", + "startedAt": "2026-08-08T12:39:15.162Z", + "finishedAt": "2026-08-08T12:39:15.288Z", + "success": true, + "passed": 8, + "failed": 0, + "fatal": null + } + ], + "scenarios": [ + { + "name": "admin-boundary-automation", + "module": "supplemental-boundaries", + "success": true, + "deploymentBlocked": false, + "passed": 18, + "failed": 0 + } + ], + "deploymentBlockers": [ + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "创建隔离拖车预约", + "evidence": "", + "code": "A0400", + "requestId": "b29d68d6-ea89-49e7-b72b-7a668dae2b17", + "traceId": "942ea3101a4d481289a31a52e724f228" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约费用、司机车辆和地址字段完整", + "evidence": "id=missing, status=missing", + "code": "A0400", + "requestId": "b29d68d6-ea89-49e7-b72b-7a668dae2b17", + "traceId": "942ea3101a4d481289a31a52e724f228" + } + ], + "coverageGaps": [ + { + "module": "supplemental-boundaries", + "scenario": "resource-occupancy", + "name": "托盘/库位真实占用删除保护", + "reason": "当前公共验收 API 未提供可安全构造并释放占用关联的独立 fixture;未操作历史资源", + "category": "no-public-fixture-api" + } + ], + "createdResources": { + "oceanBooking": { + "id": "2086069720225198081", + "marker": "ADMIN-API-20260808123912960", + "finalStatus": "RELEASED" + }, + "serviceCenterFlow": { + "appointmentId": "2086069724465639425", + "oceanBookingId": "2086069720225198081", + "marker": "ADMIN-API-20260808123912960", + "finalStatus": "CANCELLED" + } + }, + "excluded": [ + { + "scope": "dashboard", + "reason": "首页为静态演示数据,不调用后端 API" + }, + { + "scope": "hidden-prototypes", + "reason": "隐藏原型页面尚无已确认后端契约" + } + ], + "securityNote": "报告不保存登录密码、Access Token、Refresh Token、图片二进制或 OCR 原文全文。", + "steps": [ + { + "module": "authentication", + "scenario": null, + "name": "平台管理员登录", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/auth/login" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "27e23be1-5ab4-4b68-a148-145eed5da246, 2806a08e-fa81-4826-ab44-f068a40acf0e", + "traceId": "2e935f492e8d44d18e0bf7794419f335", + "evidence": "", + "checkedAt": "2026-08-08T12:39:13.333Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "admin-boundary-automation", + "name": "创建边界验收隔离仓库", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/warehouse-admin" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "77bbdfb0-062f-49de-9360-36ddbda9cda8, 44c375af-1bee-4351-bc84-52a3944b1657", + "traceId": "0bf8006b05024e21ae02c344d8ec6c4c", + "evidence": "", + "checkedAt": "2026-08-08T12:39:13.392Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "admin-boundary-automation", + "name": "创建边界验收隔离库位", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/locations?tenantId=0" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "f466e6df-a7be-4d21-88dd-84f4242d14bc, 80b547b9-35a6-4198-8fdb-7bf8f6a216ea", + "traceId": "e26d7dd14fb8455bac3c955c89c1b75f", + "evidence": "", + "checkedAt": "2026-08-08T12:39:13.434Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "admin-boundary-automation", + "name": "读取隔离库位版本", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/locations/2086069717056929794?tenantId=0&warehouseId=2086069716847214593" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "40414604-8985-4740-9691-e481a78c8f24, 9d56109d-7d40-4811-b2ed-8b3a337427da", + "traceId": "8c2505c7c450478e802b97fda0e52211", + "evidence": "", + "checkedAt": "2026-08-08T12:39:13.477Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "admin-boundary-automation", + "name": "更新隔离库位以推进版本", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "PUT", + "path": "/api/platform/v1/locations/2086069717056929794?tenantId=0&warehouseId=2086069716847214593" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "cb37bddd-160d-4264-abeb-3fc151355382, ba2ca208-e101-419a-ab9f-b8cc1c6762c3", + "traceId": "883cc491b1f9432aa33d5712ded36726", + "evidence": "version=0", + "checkedAt": "2026-08-08T12:39:13.529Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "admin-boundary-automation", + "name": "库位旧 version PUT 返回冲突", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "PUT", + "path": "/api/platform/v1/locations/2086069717056929794?tenantId=0&warehouseId=2086069716847214593" + }, + "http": 200, + "code": "A0409", + "message": "库位已被其他操作修改,请刷新后重试", + "requestId": "2ceb4209-dd6d-4fa7-af71-0ce465b54e62", + "traceId": "74cbb4759c6544a28f4e2da84bed07da", + "evidence": "HTTP=200, code=A0409", + "checkedAt": "2026-08-08T12:39:13.576Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "admin-boundary-automation", + "name": "冲突后回查库位", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/locations/2086069717056929794?tenantId=0&warehouseId=2086069716847214593" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "cf12780c-35ff-4cd1-a81f-a62fbf2b167b, ea2f0752-4a1d-4e0c-9132-5acf9caa4b82", + "traceId": "eca5068a925047e6ba639593d3129883", + "evidence": "", + "checkedAt": "2026-08-08T12:39:13.610Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "admin-boundary-automation", + "name": "库位冲突未造成部分更新", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/locations/2086069717056929794?tenantId=0&warehouseId=2086069716847214593" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "cf12780c-35ff-4cd1-a81f-a62fbf2b167b, ea2f0752-4a1d-4e0c-9132-5acf9caa4b82", + "traceId": "eca5068a925047e6ba639593d3129883", + "evidence": "name=边界库位-编辑", + "checkedAt": "2026-08-08T12:39:13.610Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "import-boundaries", + "name": "仓库空文件安全失败且不模拟导入成功", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/warehouse-admin/import?tenantId=0&dryRun=true" + }, + "http": 200, + "code": "A0422", + "message": "仓库导入文件校验失败", + "requestId": "984c5a53-50fd-4ee5-ab1b-6fbc584bf046", + "traceId": "2108daeb271d4a69906eb28eba105678", + "evidence": "HTTP=200, code=A0422, bytes=0", + "checkedAt": "2026-08-08T12:39:13.642Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "import-boundaries", + "name": "仓库缺列伪 XLSX安全失败且不模拟导入成功", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/warehouse-admin/import?tenantId=0&dryRun=true" + }, + "http": 200, + "code": "A0422", + "message": "仓库导入文件校验失败", + "requestId": "d80cbea3-50d1-4fe7-ae24-a03633f36825", + "traceId": "3de7ad0f86934831a5f2719bad4f8ab2", + "evidence": "HTTP=200, code=A0422, bytes=6", + "checkedAt": "2026-08-08T12:39:13.671Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "import-boundaries", + "name": "快递公司错误扩展名安全失败且不模拟导入成功", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/express-companies/import?tenantId=0" + }, + "http": 200, + "code": "A0422", + "message": "快递公司导入文件校验失败", + "requestId": "053c7a5b-603d-408f-8e45-571e208b7dc3", + "traceId": "5f4ec054653f4503908110169e73a2e7", + "evidence": "HTTP=200, code=A0422, bytes=27", + "checkedAt": "2026-08-08T12:39:13.709Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "import-boundaries", + "name": "往来单位非 XLSX安全失败且不模拟导入成功", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/partners/import?tenantId=0" + }, + "http": 200, + "code": "A0422", + "message": "往来单位导入文件校验失败", + "requestId": "eabe62cd-77ba-467b-8567-3e5d598b1f48", + "traceId": "cf05c0784aa14947802643e3a5fea968", + "evidence": "HTTP=200, code=A0422, bytes=27", + "checkedAt": "2026-08-08T12:39:13.732Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "admin-boundary-automation", + "name": "错误客户海外仓费用 ID 安全失败", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/iam/tenants/999999999999999999/overseas-storage-fees" + }, + "http": 200, + "code": "A0404", + "message": "海外仓费用不存在", + "requestId": "9d3c055e-fa7f-41fb-acfc-8449c1664936", + "traceId": "c925c6081fe945b88206e019a423130d", + "evidence": "HTTP=200, code=A0404", + "checkedAt": "2026-08-08T12:39:13.767Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "admin-boundary-automation", + "name": "库位列表未授权边界响应正确", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/locations?page=1&size=1&tenantId=0" + }, + "http": 401, + "code": "A0401", + "message": "未登录或令牌已失效", + "requestId": "5a30d6d1-2548", + "traceId": null, + "evidence": "HTTP=401, code=A0401", + "checkedAt": "2026-08-08T12:39:13.788Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "admin-boundary-automation", + "name": "下载中心非法页码边界响应正确", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/files/export-tasks?page=0&size=1" + }, + "http": 200, + "code": "A0422", + "message": "page.page: must be greater than or equal to 1", + "requestId": "0554b007-122f-4827-b082-a64a96e808b4", + "traceId": "8960348dde1b4a3ea03bfd25c4cdf067", + "evidence": "HTTP=200, code=A0422", + "checkedAt": "2026-08-08T12:39:13.814Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "admin-boundary-automation", + "name": "船期价格非法状态边界响应正确", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/fba-pricing/carrier-rates/price-books?status=INVALID" + }, + "http": 200, + "code": "A0400", + "message": "Bad request", + "requestId": "b49644de-d271-4897-b484-c4c54f6d64f8", + "traceId": "6a49a0491252443b84af064d30e7bc16", + "evidence": "HTTP=200, code=A0400", + "checkedAt": "2026-08-08T12:39:13.841Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "admin-boundary-automation", + "name": "停用隔离库位以便清理", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "PATCH", + "path": "/api/platform/v1/locations/2086069717056929794/status?tenantId=0&warehouseId=2086069716847214593" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "400b0b21-fcd0-4cfd-a1c0-c14a4810ab12, 32bf088f-6f00-410d-9ce2-87c995a600fa", + "traceId": "33e135d3d00b44c09f06cc29e1c68582", + "evidence": "", + "checkedAt": "2026-08-08T12:39:13.872Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "admin-boundary-automation", + "name": "删除隔离库位", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "DELETE", + "path": "/api/platform/v1/locations/2086069717056929794?tenantId=0&warehouseId=2086069716847214593&version=2" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "efebbe74-62a5-4a89-856b-9374bd3ea26c, 72022a6b-1952-4f7b-8300-2c20c60284fe", + "traceId": "a59bd2c2287b46dd9bbabdbeee02053e", + "evidence": "", + "checkedAt": "2026-08-08T12:39:13.912Z" + }, + { + "module": "supplemental-boundaries", + "scenario": "admin-boundary-automation", + "name": "停用隔离仓库", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "PATCH", + "path": "/api/platform/v1/warehouse-admin/2086069716847214593/status?tenantId=0&status=INACTIVE" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "877ea99b-7867-4493-80b9-ebe6b1bdae4d, 5f397978-3e8b-43ec-b198-340fbe2c399e", + "traceId": "d828eed38c3c4c15909fdd84bbc04ad3", + "evidence": "", + "checkedAt": "2026-08-08T12:39:13.941Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "订舱列表分页与 keyword 查询", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/ocean-bookings?page=1&size=5&keyword=ADMIN-API-20260808123912960" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "838d1944-d0e0-4bc5-8e60-fdaa78ecbdcc, f86f0234-bf8a-4b96-bdb9-42c1263d6a4b", + "traceId": "b21cef690d0449a98124e9563bac3bcf", + "evidence": "", + "checkedAt": "2026-08-08T12:39:13.969Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "订舱列表分页结构正确", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/ocean-bookings?page=1&size=5&keyword=ADMIN-API-20260808123912960" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "838d1944-d0e0-4bc5-8e60-fdaa78ecbdcc, f86f0234-bf8a-4b96-bdb9-42c1263d6a4b", + "traceId": "b21cef690d0449a98124e9563bac3bcf", + "evidence": "records=0", + "checkedAt": "2026-08-08T12:39:13.969Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "订舱 DRAFT 状态筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/ocean-bookings?page=1&size=5&status=DRAFT" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "6fb3a995-00f7-4296-8f01-11c71eb3cde1, 8bd6b9bd-7f1a-42e0-8dea-31cdd52b5a08", + "traceId": "62ab7fa9fc3a4023b1f343b225bced65", + "evidence": "HTTP=200, code=200, records=0", + "checkedAt": "2026-08-08T12:39:14.000Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "订舱 SUBMITTED 状态筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/ocean-bookings?page=1&size=5&status=SUBMITTED" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "a3148d32-9460-4a8c-9a28-e51d2c1c019f, 30d669e5-5a31-4528-93cf-2cc391189882", + "traceId": "871ae9e9005c45f4ae34ea24271b213e", + "evidence": "HTTP=200, code=200, records=0", + "checkedAt": "2026-08-08T12:39:14.031Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "订舱 CONFIRMED 状态筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/ocean-bookings?page=1&size=5&status=CONFIRMED" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "6b224895-b376-4145-a18a-6b06af3b05b9, 98add4a6-b2d0-4d2b-8f05-6da5ce10e7be", + "traceId": "bceeffdc4bc34e23a6f5484914dd1a5b", + "evidence": "HTTP=200, code=200, records=0", + "checkedAt": "2026-08-08T12:39:14.060Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "订舱 RELEASED 状态筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/ocean-bookings?page=1&size=5&status=RELEASED" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "71eab475-2b70-4fee-be4b-da10ced7dd08, 52ac102e-cc62-4f32-925a-80d163cfc7fa", + "traceId": "545b1a03cfcb4268af3904913e527607", + "evidence": "HTTP=200, code=200, records=5", + "checkedAt": "2026-08-08T12:39:14.093Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "订舱 FAILED 状态筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/ocean-bookings?page=1&size=5&status=FAILED" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "af43693e-aaff-4f83-9153-70816b6aa621, 6a6501f4-1465-4d52-af21-33c467d0c2aa", + "traceId": "f443bec27cc84aae9113e98f28f96907", + "evidence": "HTTP=200, code=200, records=0", + "checkedAt": "2026-08-08T12:39:14.121Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "订舱 CANCELLED 状态筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/ocean-bookings?page=1&size=5&status=CANCELLED" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "df30c45a-64eb-454c-b3a9-8a849c362c7e, 49c2cfa0-764d-4a33-af07-0c203325752e", + "traceId": "8f9758a3959a40e78d1003af11288db0", + "evidence": "HTTP=200, code=200, records=0", + "checkedAt": "2026-08-08T12:39:14.147Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "创建隔离海运订舱", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/ocean-bookings" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "fdc28464-8bc7-49b4-8427-def70afe0a19, 554cecfb-0cc9-45c1-8248-a722425146c6", + "traceId": "7ef2984f02434602a26f69b95a92f4aa", + "evidence": "key=ADMIN-API-20260808123912960-ocean-create", + "checkedAt": "2026-08-08T12:39:14.204Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "订舱 DTO 字段、DRAFT 和9类关联字段完整", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/ocean-bookings" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "fdc28464-8bc7-49b4-8427-def70afe0a19, 554cecfb-0cc9-45c1-8248-a722425146c6", + "traceId": "7ef2984f02434602a26f69b95a92f4aa", + "evidence": "bookingId=2086069720225198081, parties=3, requirements=1", + "checkedAt": "2026-08-08T12:39:14.204Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "创建 Idempotency-Key 重放返回同一订舱", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/ocean-bookings" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "7582c0f1-2acf-43da-a85d-c03d2277443a, 89b7c670-2370-4cdc-83ff-8d834f64b6ee", + "traceId": "7920ff2de0944a1c97ac3a3efdc1c565", + "evidence": "first=2086069720225198081, replay=2086069720225198081", + "checkedAt": "2026-08-08T12:39:14.251Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "编辑 DRAFT 订舱", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "PUT", + "path": "/api/platform/v1/ocean-bookings/2086069720225198081" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "5feedbb8-8ecf-4d32-b2df-fea6c1571291, 8ebd99f0-4c79-4050-b2df-d3102afcfd83", + "traceId": "8ae25d117807491ea99cd4141ef39306", + "evidence": "version=0", + "checkedAt": "2026-08-08T12:39:14.328Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "订舱旧版本编辑返回冲突", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "PUT", + "path": "/api/platform/v1/ocean-bookings/2086069720225198081" + }, + "http": 200, + "code": "A0409", + "message": "数据已被其他人修改,请刷新后重试", + "requestId": "4be08ff3-13c3-42bd-9f3f-12ff5f69119c", + "traceId": "7a70cf6cd4c742d4b584ce9947600768", + "evidence": "HTTP=200, code=A0409", + "checkedAt": "2026-08-08T12:39:14.361Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "冲突后回查订舱", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/ocean-bookings/2086069720225198081" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "8e8bc2b0-7da1-443e-b206-3f5c1936622d, b559cb67-b7a1-4768-8010-5b377ca2c833", + "traceId": "76f89579001c470d98f5a189622e075f", + "evidence": "", + "checkedAt": "2026-08-08T12:39:14.387Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "订舱冲突未部分更新", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/ocean-bookings/2086069720225198081" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "8e8bc2b0-7da1-443e-b206-3f5c1936622d, b559cb67-b7a1-4768-8010-5b377ca2c833", + "traceId": "76f89579001c470d98f5a189622e075f", + "evidence": "vessel=编辑船-8123912960", + "checkedAt": "2026-08-08T12:39:14.387Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "提交订舱", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/ocean-bookings/2086069720225198081/submit" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "3df7f688-27b5-497c-a804-4fd1a019266f, f73d8c8c-723a-4497-8e23-0a0fa3d16b49", + "traceId": "5e138d40cef54c449b3706da66014f50", + "evidence": "status=SUBMITTED", + "checkedAt": "2026-08-08T12:39:14.434Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "确认订舱", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/ocean-bookings/2086069720225198081/confirm" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "525d44a3-8d81-444b-99a7-862fb67481eb, dcee6868-35d2-4cdf-b18d-351a7863a018", + "traceId": "2dd987427f874c2a9954770271e31819", + "evidence": "status=CONFIRMED", + "checkedAt": "2026-08-08T12:39:14.492Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "申请改船", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/ocean-bookings/2086069720225198081/change-request" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "ea6754bb-0ba4-4de8-9fef-72d4f8aad101, a0c38ddb-556a-4b45-b8d8-63a3f4b3622d", + "traceId": "d36fbd7e508f4ebab2ccf3e8a1d27936", + "evidence": "", + "checkedAt": "2026-08-08T12:39:14.571Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "确认改船", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/ocean-bookings/2086069720225198081/change-confirm" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "7f4b6a2c-cd3b-40a0-b4ca-a00622904658, da9f7ed2-a790-44ab-ad1a-ca2e4744efcb", + "traceId": "b162040e2edd4b5abf41006a01e52670", + "evidence": "status=CONFIRMED", + "checkedAt": "2026-08-08T12:39:14.626Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "放舱", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/ocean-bookings/2086069720225198081/release" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "8a87427d-76d6-4134-9818-8f182f2ae6a5, ab8fe3ad-9876-4ef5-92c4-b5191b37d767", + "traceId": "4ae513a3054c4e07aa3ede6138ac38dc", + "evidence": "status=RELEASED", + "checkedAt": "2026-08-08T12:39:14.676Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "回查 RELEASED 订舱详情", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/ocean-bookings/2086069720225198081" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "a5d9446f-7255-4512-9e48-35bcabebea67, 69d63445-1fa7-4de6-9af5-a43e5b78f657", + "traceId": "7b78ee57dd1c4d18885307c684899fec", + "evidence": "", + "checkedAt": "2026-08-08T12:39:14.719Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "订舱状态历史、审计操作者和终态完整", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/ocean-bookings/2086069720225198081" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "a5d9446f-7255-4512-9e48-35bcabebea67, 69d63445-1fa7-4de6-9af5-a43e5b78f657", + "traceId": "7b78ee57dd1c4d18885307c684899fec", + "evidence": "status=RELEASED, histories=6", + "checkedAt": "2026-08-08T12:39:14.719Z" + }, + { + "module": "ocean-bookings", + "scenario": "ocean-booking-lifecycle", + "name": "不存在订舱详情安全失败", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/ocean-bookings/999999999999999999" + }, + "http": 200, + "code": "A0404", + "message": "订舱单不存在", + "requestId": "57fec596-0f7c-41e6-923c-cac49afc4596", + "traceId": "4414c91d3756454f9cbfa36e877aec84", + "evidence": "HTTP=200, code=A0404", + "checkedAt": "2026-08-08T12:39:14.746Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约分页 keyword 查询", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments?page=1&size=5&keyword=ADMIN-API-20260808123912960" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "0fc2acbc-219c-4b9f-ad7f-5b5d791bacf8, ccb2d4c0-9bee-4ad2-80a9-feec1f6d3465", + "traceId": "5d206d95e86e4d8cbfe51577c23f9346", + "evidence": "", + "checkedAt": "2026-08-08T12:39:14.778Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约分页结构正确", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments?page=1&size=5&keyword=ADMIN-API-20260808123912960" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "0fc2acbc-219c-4b9f-ad7f-5b5d791bacf8, ccb2d4c0-9bee-4ad2-80a9-feec1f6d3465", + "traceId": "5d206d95e86e4d8cbfe51577c23f9346", + "evidence": "records=0", + "checkedAt": "2026-08-08T12:39:14.778Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约 DRAFT 筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments?page=1&size=5&status=DRAFT" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "e4ab1d22-c88f-434d-af62-afe1c53e8406, e5d5acfe-9d08-4524-8931-a0a0478d1086", + "traceId": "1dc2436ca66f4412828a7406b12ff759", + "evidence": "HTTP=200, code=200, records=0", + "checkedAt": "2026-08-08T12:39:14.810Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约 PENDING_DISPATCH 筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments?page=1&size=5&status=PENDING_DISPATCH" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "4f9e0dab-f995-49ba-8001-a279b2437e80, bbf13201-f1e5-48fb-82ca-f8c2a84307bb", + "traceId": "6d4fb6f346104edf8370dc199df67044", + "evidence": "HTTP=200, code=200, records=0", + "checkedAt": "2026-08-08T12:39:14.838Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约 DISPATCHED 筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments?page=1&size=5&status=DISPATCHED" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "d5aa5c75-1540-420c-8c1f-e562781b93b3, 19bb03d7-ce33-4b21-97b7-02d9dda040f5", + "traceId": "5c8c13b07dde4f0aa9db7df873e768ad", + "evidence": "HTTP=200, code=200, records=0", + "checkedAt": "2026-08-08T12:39:14.871Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约 PICKUP_IN_PROGRESS 筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments?page=1&size=5&status=PICKUP_IN_PROGRESS" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "0ba03f22-1fba-4162-ad1b-3785b3874012, 3c84534f-58f1-4bd8-ac1d-eeff60684f50", + "traceId": "56ef5d76865c4c9d8466ec9aa192d021", + "evidence": "HTTP=200, code=200, records=0", + "checkedAt": "2026-08-08T12:39:14.895Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约 ARRIVED_WAREHOUSE 筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments?page=1&size=5&status=ARRIVED_WAREHOUSE" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "96ec572b-94cf-47c0-8a4d-0128f80cd8eb, 629b6797-f6d9-4449-b170-79e4f5ec98d6", + "traceId": "ff2d0970064a4e00a41d74bef34af339", + "evidence": "HTTP=200, code=200, records=0", + "checkedAt": "2026-08-08T12:39:14.933Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约 LOADING 筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments?page=1&size=5&status=LOADING" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "af9132e5-c87c-4f94-847d-c6c7a36f8c62, 62db5e34-793e-4fa5-a3af-883e670995b1", + "traceId": "f52efe5b67a44e81b391ebb8dd638989", + "evidence": "HTTP=200, code=200, records=0", + "checkedAt": "2026-08-08T12:39:14.962Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约 DEPARTED 筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments?page=1&size=5&status=DEPARTED" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "e6a84b39-b1c3-4854-8d4c-8449aac673d6, 8d2ed67d-1462-41f4-8249-c5acf635a6be", + "traceId": "cafe03f3dd3e4bee87afcd12c7b3fb28", + "evidence": "HTTP=200, code=200, records=0", + "checkedAt": "2026-08-08T12:39:14.994Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约 COMPLETED 筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments?page=1&size=5&status=COMPLETED" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "b2df8490-c986-4071-92d9-a906dd39c2d9, 82110bef-69f4-49e3-a8e1-59ecd3046eb4", + "traceId": "2e8a4827631f4c95afc2adc594574c32", + "evidence": "HTTP=200, code=200, records=5", + "checkedAt": "2026-08-08T12:39:15.034Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约 RESCHEDULED 筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments?page=1&size=5&status=RESCHEDULED" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "f7f2bce8-6eec-49cb-b095-84b5ab8fc6e6, 9b8fd769-84c2-474d-83a1-2818198dbbb8", + "traceId": "d6c833639e1c4121a6bc193fb7fbdfc5", + "evidence": "HTTP=200, code=200, records=0", + "checkedAt": "2026-08-08T12:39:15.074Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约 EXCEPTION 筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments?page=1&size=5&status=EXCEPTION" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "b1375607-2a09-4661-a616-057fcdbbc401, 88841d51-7f83-42ef-92e4-d6190e500ec9", + "traceId": "fe6d71f583ab4752bdc48bb9c55e215f", + "evidence": "HTTP=200, code=200, records=0", + "checkedAt": "2026-08-08T12:39:15.103Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约 CANCELLED 筛选", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments?page=1&size=5&status=CANCELLED" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "18cb8cca-642b-4e90-9a9d-3c9698e4ac18, 54d5faec-86fc-4ed4-a0ff-b180163ee7a4", + "traceId": "752eea2206f745109949a3aecdbcb13e", + "evidence": "HTTP=200, code=200, records=5", + "checkedAt": "2026-08-08T12:39:15.135Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "创建隔离拖车预约", + "passed": false, + "deploymentBlocker": true, + "request": { + "method": "POST", + "path": "/api/platform/v1/truck-appointments" + }, + "http": 200, + "code": "A0400", + "message": "oceanBookingId不能为空", + "requestId": "b29d68d6-ea89-49e7-b72b-7a668dae2b17", + "traceId": "942ea3101a4d481289a31a52e724f228", + "evidence": "", + "checkedAt": "2026-08-08T12:39:15.161Z" + }, + { + "module": "truck-appointments", + "scenario": "truck-appointment-lifecycle", + "name": "拖车预约费用、司机车辆和地址字段完整", + "passed": false, + "deploymentBlocker": true, + "request": { + "method": "POST", + "path": "/api/platform/v1/truck-appointments" + }, + "http": 200, + "code": "A0400", + "message": "oceanBookingId不能为空", + "requestId": "b29d68d6-ea89-49e7-b72b-7a668dae2b17", + "traceId": "942ea3101a4d481289a31a52e724f228", + "evidence": "id=missing, status=missing", + "checkedAt": "2026-08-08T12:39:15.161Z" + }, + { + "module": "service-center-flow", + "scenario": "service-center-cross-flow", + "name": "创建关联海运订舱的拖车预约", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/truck-appointments" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "dbbcf402-7bef-4b37-8891-4f6c96233e9d, aebe774c-9e82-4610-a98e-fd8865bd26d3", + "traceId": "a5d06aee287e49bcaa2dc7dbab7413e1", + "evidence": "oceanBookingId=2086069720225198081", + "checkedAt": "2026-08-08T12:39:15.201Z" + }, + { + "module": "service-center-flow", + "scenario": "service-center-cross-flow", + "name": "拖车预约关联订舱 ID、版本和审计字段完整", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/truck-appointments" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "dbbcf402-7bef-4b37-8891-4f6c96233e9d, aebe774c-9e82-4610-a98e-fd8865bd26d3", + "traceId": "a5d06aee287e49bcaa2dc7dbab7413e1", + "evidence": "appointmentId=2086069724465639425, oceanBookingId=2086069720225198081, version=0", + "checkedAt": "2026-08-08T12:39:15.201Z" + }, + { + "module": "service-center-flow", + "scenario": "service-center-cross-flow", + "name": "取消跨服务链路拖车预约", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/truck-appointments/2086069724465639425/cancel" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "46455b44-6df8-4c35-8092-87d6e95a6510, 314247b3-ca33-48dd-99c7-45178300dd7d", + "traceId": "f843483857c4485b80e8ffa90dfdfd33", + "evidence": "", + "checkedAt": "2026-08-08T12:39:15.231Z" + }, + { + "module": "service-center-flow", + "scenario": "service-center-cross-flow", + "name": "跨服务链路安全终态为 CANCELLED", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "POST", + "path": "/api/platform/v1/truck-appointments/2086069724465639425/cancel" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "46455b44-6df8-4c35-8092-87d6e95a6510, 314247b3-ca33-48dd-99c7-45178300dd7d", + "traceId": "f843483857c4485b80e8ffa90dfdfd33", + "evidence": "status=CANCELLED", + "checkedAt": "2026-08-08T12:39:15.231Z" + }, + { + "module": "service-center-flow", + "scenario": "service-center-cross-flow", + "name": "回查跨服务链路安全终态", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments/2086069724465639425" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "d0184f69-2fd4-4062-89d2-1203f9b18945, feb6c29e-cbcb-41ef-bfb8-abb7a16dc51b", + "traceId": "5f80e8363c43417e8b3a35823717a75b", + "evidence": "", + "checkedAt": "2026-08-08T12:39:15.255Z" + }, + { + "module": "service-center-flow", + "scenario": "service-center-cross-flow", + "name": "跨服务链路终态持久化且关联订舱未漂移", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments/2086069724465639425" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "d0184f69-2fd4-4062-89d2-1203f9b18945, feb6c29e-cbcb-41ef-bfb8-abb7a16dc51b", + "traceId": "5f80e8363c43417e8b3a35823717a75b", + "evidence": "status=CANCELLED, oceanBookingId=2086069720225198081", + "checkedAt": "2026-08-08T12:39:15.255Z" + }, + { + "module": "service-center-flow", + "scenario": "service-center-cross-flow", + "name": "查询跨服务链路拖车预约状态历史", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments/2086069724465639425/history" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "740d299a-e3f9-4617-ab0d-947ef0ce673a, 0e100441-3439-4a94-9de7-0471a59a1311", + "traceId": "7b11fb3a58364646b48b4f0a91b075e9", + "evidence": "", + "checkedAt": "2026-08-08T12:39:15.288Z" + }, + { + "module": "service-center-flow", + "scenario": "service-center-cross-flow", + "name": "跨服务链路历史包含归属、状态、操作者、时间和备注", + "passed": true, + "deploymentBlocker": false, + "request": { + "method": "GET", + "path": "/api/platform/v1/truck-appointments/2086069724465639425/history" + }, + "http": 200, + "code": "200", + "message": "success", + "requestId": "740d299a-e3f9-4617-ab0d-947ef0ce673a, 0e100441-3439-4a94-9de7-0471a59a1311", + "traceId": "7b11fb3a58364646b48b4f0a91b075e9", + "evidence": "history=2, cancelFrom=DRAFT, cancelTo=CANCELLED", + "checkedAt": "2026-08-08T12:39:15.288Z" + } + ] +} diff --git a/scripts/admin-test-env-modules/truck-appointments.mjs b/scripts/admin-test-env-modules/truck-appointments.mjs index 7fabc8a10..c5e3068c0 100644 --- a/scripts/admin-test-env-modules/truck-appointments.mjs +++ b/scripts/admin-test-env-modules/truck-appointments.mjs @@ -1,28 +1,91 @@ const MODULE = 'truck-appointments' const OPTIONS = { scenario: 'truck-appointment-lifecycle', deploymentBlocker: true } const BASE = '/api/platform/v1/truck-appointments' -function id(v) { return v == null ? '' : String(v) } -function codeOf(r) { return r?.body?.code == null ? 'missing' : String(r.body.code) } -function missing(r) { return r?.http === 404 || r?.http === 405 || r?.http === 503 } -function failure(r) { return [400, 401, 403, 404, 409, 503].includes(r?.http) || (r?.http === 200 && codeOf(r) !== '200') } -async function req(context, method, path, body, headers = {}) { try { const response = await fetch(`${context.options.gateway}${path}`, { method, headers: { Accept: 'application/json', Authorization: `Bearer ${context.token}`, ...(body === undefined ? {} : { 'Content-Type': 'application/json; charset=utf-8' }), ...headers }, body: body === undefined ? undefined : JSON.stringify(body), signal: AbortSignal.timeout(60_000) }); const raw = await response.text(); let payload = null; try { payload = raw ? JSON.parse(raw) : null } catch {} return { method, path, http: response.status, body: payload, raw: payload === null ? raw.slice(0, 500) : null, requestId: payload?.requestId || response.headers.get('x-request-id'), traceId: payload?.traceId || response.headers.get('x-trace-id') } } catch (e) { return { method, path, http: 0, body: null, raw: String(e), requestId: null, traceId: null } } } -function data(r) { return String(r?.body?.code) === '200' ? r.body.data : null } -function payload(context, suffix, version = 0) { return { outboundOrderId: null, oceanBookingId: null, containerBookingId: null, loadingPlanId: null, warehouseId: 193000000000000001, customerId: 10001, customerName: `拖车验收客户-${suffix}`, carrierId: null, carrierName: `承运商-${suffix}`, fleetContact: '车队联系人', fleetPhone: '13800000004', driverName: '司机验收', driverPhone: '13800000005', driverIdCard: null, vehicleNo: `粤B-${suffix.slice(-6)}`, storeName: `门店-${suffix}`, storeContact: '门店联系人', storePhone: '13800000006', storeAddress: '深圳市南山区验收地址', storeCity: '深圳市', storeZipcode: '518000', packageCount: 10, grossWeightKg: 100, volumeCbm: 2.5, palletCount: 1, poNo: `PO-${suffix}`, plannedLoadingAt: '2026-09-02T08:00:00', transitMinutes: 120, payableAmount: 100, receivableAmount: 150, currency: 'RMB', remark: context.marker, expectedVersion: version } } -export async function run(context) { const suffix = context.marker.replace(/\D/g, '').slice(-10); const list = await req(context, 'GET', `${BASE}?page=1&size=5&keyword=${encodeURIComponent(context.marker)}`); if (missing(list) || list.http === 0) { context.addStep(MODULE, '拖车预约服务契约已部署', list, false, `入口 ${BASE} 不可用:HTTP=${list.http}, code=${codeOf(list)}`, OPTIONS); return } const page = context.apiSuccess(MODULE, '拖车预约分页 keyword 查询', list, '', OPTIONS); context.assert(MODULE, '拖车预约分页结构正确', list, Array.isArray(page?.records), `records=${page?.records?.length ?? 'n/a'}`, OPTIONS); for (const status of ['DRAFT','PENDING_DISPATCH','DISPATCHED','PICKUP_IN_PROGRESS','ARRIVED_WAREHOUSE','LOADING','DEPARTED','COMPLETED','RESCHEDULED','EXCEPTION','CANCELLED']) { const r = await req(context, 'GET', `${BASE}?page=1&size=5&status=${status}`); const d = data(r); context.addStep(MODULE, `拖车预约 ${status} 筛选`, r, r.http === 200 && codeOf(r) === '200' && Array.isArray(d?.records) && d.records.every((x) => x.status === status), `HTTP=${r.http}, code=${codeOf(r)}, records=${d?.records?.length ?? 'n/a'}`, OPTIONS) } - const createResponse = await req(context, 'POST', BASE, payload(context, suffix)); const appointment = context.apiSuccess(MODULE, '创建隔离拖车预约', createResponse, '', OPTIONS); const appointmentId = id(appointment?.id); context.assert(MODULE, '拖车预约费用、司机车辆和地址字段完整', createResponse, Boolean(appointmentId) && appointment?.status === 'DRAFT' && appointment?.payableAmount != null && appointment?.receivableAmount != null, `id=${appointmentId || 'missing'}, status=${appointment?.status || 'missing'}`, OPTIONS); if (!appointmentId) return; context.createdResources.truckAppointment = { id: appointmentId, marker: context.marker, finalStatus: 'CANCELLED' }; const path = `${BASE}/${appointmentId}`; let version = Number(appointment.version); const edit = await req(context, 'PUT', path, { ...payload(context, suffix, version), vehicleNo: `粤C-${suffix.slice(-6)}` }); const edited = context.apiSuccess(MODULE, '编辑拖车预约', edit, `version=${version}`, OPTIONS); version = Number(edited?.version); const stale = await req(context, 'PUT', path, { ...payload(context, suffix, 0), vehicleNo: `STALE-${suffix}` }); context.addStep(MODULE, '拖车预约旧版本编辑返回冲突', stale, stale.http === 200 && ['A0409','409'].includes(codeOf(stale)), `HTTP=${stale.http}, code=${codeOf(stale)}`, OPTIONS); const after = await req(context, 'GET', path); const ad = data(after); context.apiSuccess(MODULE, '冲突后回查拖车预约', after, '', OPTIONS); context.assert(MODULE, '拖车预约冲突未部分更新', after, ad?.vehicleNo === edited?.vehicleNo, `vehicleNo=${ad?.vehicleNo || 'missing'}`, OPTIONS); version = Number(ad?.version); const action = async (name, endpoint, expected) => { const r = await req(context, 'POST', `${path}/${endpoint}`, { expectedVersion: expected, reason: context.marker }, { 'Idempotency-Key': `${context.marker}-${endpoint}` }); const d = context.apiSuccess(MODULE, name, r, '', OPTIONS); context.assert(MODULE, `${name} 状态返回`, r, Boolean(d?.status), `status=${d?.status || 'missing'}`, OPTIONS); version = Number(d?.version); return d }; for (const [name, endpoint] of [['提交预约','submit'],['派车','dispatch'],['开始提货','pickup'],['到仓','arrive'],['开始装货','load'],['离场','depart'],['完成','complete']]) await action(name, endpoint, version); const final = await req(context, 'GET', path); const fd = data(final); context.apiSuccess(MODULE, '回查 COMPLETED 拖车预约', final, '', OPTIONS); context.assert(MODULE, '拖车预约状态终态和费用快照正确', final, fd?.status === 'COMPLETED' && fd?.payableAmount != null && fd?.receivableAmount != null, `status=${fd?.status || 'missing'}`, OPTIONS) - const historyResponse = await req(context, 'GET', `${path}/history`) - const history = context.apiSuccess(MODULE, '查询拖车预约状态历史', historyResponse, '', OPTIONS) - const expectedActions = ['CREATE', 'EDIT', 'SUBMIT', 'DISPATCH', 'PICKUP', 'ARRIVE', 'LOAD', 'DEPART', 'COMPLETE'] - const actualActions = Array.isArray(history) ? history.map((item) => item?.action) : [] - context.assert(MODULE, '拖车预约历史动作和状态链完整', historyResponse, - Array.isArray(history) && expectedActions.every((value) => actualActions.includes(value)) - && history.every((item) => id(item?.appointmentId) === appointmentId - && Boolean(item?.action) && Object.hasOwn(item, 'fromStatus') && Boolean(item?.toStatus) - && Boolean(item?.operatorId) && Boolean(item?.operatorName) && Boolean(item?.createdAt)), - `history=${history?.length ?? 'n/a'}, actions=${actualActions.join(',')}`, OPTIONS) +function id(value) { return value == null ? '' : String(value) } +function codeOf(response) { return response?.body?.code == null ? 'missing' : String(response.body.code) } +function missing(response) { return response?.http === 404 || response?.http === 405 || response?.http === 503 } +function failure(response) { return [400, 401, 403, 404, 409, 503].includes(response?.http) || (response?.http === 200 && codeOf(response) !== '200') } +function data(response) { return codeOf(response) === '200' ? response.body.data : null } - const missingHistory = await req(context, 'GET', `${BASE}/999999999999999999/history`) - context.addStep(MODULE, '不存在预约不能读取状态历史', missingHistory, - failure(missingHistory), `HTTP=${missingHistory.http}, code=${codeOf(missingHistory)}`, OPTIONS) +async function request(context, method, path, body, headers = {}) { + try { + const response = await fetch(`${context.options.gateway}${path}`, { + method, + headers: { Accept: 'application/json', Authorization: `Bearer ${context.token}`, ...(body === undefined ? {} : { 'Content-Type': 'application/json; charset=utf-8' }), ...headers }, + body: body === undefined ? undefined : JSON.stringify(body), signal: AbortSignal.timeout(60_000), + }) + const raw = await response.text(); let payload = null + try { payload = raw ? JSON.parse(raw) : null } catch { /* bounded raw evidence */ } + return { method, path, http: response.status, body: payload, raw: payload === null ? raw.slice(0, 500) : null, + requestId: payload?.requestId || response.headers.get('x-request-id'), traceId: payload?.traceId || response.headers.get('x-trace-id') } + } catch (error) { return { method, path, http: 0, body: null, raw: String(error), requestId: null, traceId: null } } +} + +async function uploadAttachment(context, appointmentId) { + const path = `${BASE}/${appointmentId}/attachments/upload?attachmentType=ACCEPTANCE_EVIDENCE` + const form = new FormData() + form.append('file', new Blob([new TextEncoder().encode(context.marker)], { type: 'text/plain' }), `${context.marker}-truck.txt`) + try { + const response = await fetch(`${context.options.gateway}${path}`, { method: 'POST', headers: { Accept: 'application/json', Authorization: `Bearer ${context.token}` }, body: form, signal: AbortSignal.timeout(60_000) }) + const raw = await response.text(); let payload = null + try { payload = raw ? JSON.parse(raw) : null } catch { /* bounded raw evidence */ } + return { method: 'POST', path, http: response.status, body: payload, raw: payload === null ? raw.slice(0, 500) : null, + requestId: payload?.requestId || response.headers.get('x-request-id'), traceId: payload?.traceId || response.headers.get('x-trace-id') } + } catch (error) { return { method: 'POST', path, http: 0, body: null, raw: String(error), requestId: null, traceId: null } } +} + +function payload(context, suffix, version = 0) { + return { + outboundOrderId: null, oceanBookingId: context.createdResources?.oceanBooking?.id || null, containerBookingId: null, loadingPlanId: null, + warehouseId: '193000000000000001', customerId: '10001', customerName: `拖车验收客户-${suffix}`, + carrierId: null, carrierName: `承运商-${suffix}`, fleetContact: '车队联系人', fleetPhone: '13800000004', + driverName: '司机验收', driverPhone: '13800000005', driverIdCard: null, vehicleNo: `粤B-${suffix.slice(-6)}`, + storeName: `门店-${suffix}`, storeContact: '门店联系人', storePhone: '13800000006', storeAddress: '深圳市南山区验收地址', + storeCity: '深圳市', storeZipcode: '518000', packageCount: 10, grossWeightKg: 100, volumeCbm: 2.5, + palletCount: 1, poNo: `PO-${suffix}`, plannedLoadingAt: '2026-09-02T08:00:00', transitMinutes: 120, + payableAmount: 100, receivableAmount: 150, currency: 'RMB', remark: context.marker, expectedVersion: version, + } +} + +export async function run(context) { + const suffix = context.marker.replace(/\D/g, '').slice(-10) + const list = await request(context, 'GET', `${BASE}?page=1&size=5&keyword=${encodeURIComponent(context.marker)}`) + if (missing(list) || list.http === 0) { context.addStep(MODULE, '拖车预约服务契约已部署', list, false, `入口 ${BASE} 不可用:HTTP=${list.http}, code=${codeOf(list)}`, OPTIONS); return } + const page = context.apiSuccess(MODULE, '拖车预约分页 keyword 查询', list, '', OPTIONS) + context.assert(MODULE, '拖车预约分页结构正确', list, Array.isArray(page?.records), `records=${page?.records?.length ?? 'n/a'}`, OPTIONS) + for (const status of ['DRAFT','PENDING_DISPATCH','DISPATCHED','PICKUP_IN_PROGRESS','ARRIVED_WAREHOUSE','LOADING','DEPARTED','COMPLETED','RESCHEDULED','EXCEPTION','CANCELLED']) { + const response = await request(context, 'GET', `${BASE}?page=1&size=5&status=${status}`); const result = data(response) + context.addStep(MODULE, `拖车预约 ${status} 筛选`, response, response.http === 200 && codeOf(response) === '200' && Array.isArray(result?.records) && result.records.every((item) => item.status === status), `HTTP=${response.http}, code=${codeOf(response)}, records=${result?.records?.length ?? 'n/a'}`, OPTIONS) + } + + const createResponse = await request(context, 'POST', BASE, payload(context, suffix)); const appointment = context.apiSuccess(MODULE, '创建隔离拖车预约', createResponse, '', OPTIONS) + const appointmentId = id(appointment?.id) + context.assert(MODULE, '拖车预约费用、司机车辆和地址字段完整', createResponse, Boolean(appointmentId) && appointment?.status === 'DRAFT' && appointment?.payableAmount != null && appointment?.receivableAmount != null, `id=${appointmentId || 'missing'}, status=${appointment?.status || 'missing'}`, OPTIONS) + if (!appointmentId) return + context.createdResources.truckAppointment = { id: appointmentId, marker: context.marker, finalStatus: 'COMPLETED' } + const path = `${BASE}/${appointmentId}` + + const upload = await uploadAttachment(context, appointmentId); const attachment = context.apiSuccess(MODULE, '上传本轮拖车预约文本附件', upload, `fileName=${context.marker}-truck.txt`, OPTIONS) + const attachmentId = id(attachment?.id) + context.assert(MODULE, '附件引用归属、类型和哈希元数据完整', upload, Boolean(attachmentId) && id(attachment?.appointmentId) === appointmentId && attachment?.attachmentType === 'ACCEPTANCE_EVIDENCE' && Boolean(attachment?.fileId) && Boolean(attachment?.fileHash), `attachmentId=${attachmentId || 'missing'}, fileId=${attachment?.fileId || 'missing'}`, OPTIONS) + const attachments = await request(context, 'GET', `${path}/attachments`); const attachmentList = context.apiSuccess(MODULE, '查询拖车预约附件列表', attachments, '', OPTIONS) + context.assert(MODULE, '附件列表包含本轮上传引用', attachments, Array.isArray(attachmentList) && attachmentList.some((item) => id(item.id) === attachmentId), `attachments=${attachmentList?.length ?? 'n/a'}`, OPTIONS) + const forged = await request(context, 'POST', `${path}/attachments`, { fileId: '999999999999999999', attachmentType: 'ACCEPTANCE_EVIDENCE', fileName: `${context.marker}-forged.txt`, fileHash: 'forged' }) + context.addStep(MODULE, '伪造附件 fileId 安全拒绝', forged, failure(forged), `HTTP=${forged.http}, code=${codeOf(forged)}`, OPTIONS) + if (attachmentId) { const removed = await request(context, 'DELETE', `${path}/attachments/${attachmentId}`); context.apiSuccess(MODULE, '删除本轮拖车预约附件引用', removed, `attachmentId=${attachmentId}`, OPTIONS) } + + let version = Number(appointment.version) + const edit = await request(context, 'PUT', path, { ...payload(context, suffix, version), vehicleNo: `粤C-${suffix.slice(-6)}` }); const edited = context.apiSuccess(MODULE, '编辑拖车预约', edit, `version=${version}`, OPTIONS); version = Number(edited?.version) + const stale = await request(context, 'PUT', path, { ...payload(context, suffix, 0), vehicleNo: `STALE-${suffix}` }) + context.addStep(MODULE, '拖车预约旧版本编辑返回冲突', stale, stale.http === 200 && ['A0409','409'].includes(codeOf(stale)), `HTTP=${stale.http}, code=${codeOf(stale)}`, OPTIONS) + const after = await request(context, 'GET', path); const afterData = data(after); context.apiSuccess(MODULE, '冲突后回查拖车预约', after, '', OPTIONS) + context.assert(MODULE, '拖车预约冲突未部分更新', after, afterData?.vehicleNo === edited?.vehicleNo, `vehicleNo=${afterData?.vehicleNo || 'missing'}`, OPTIONS); version = Number(afterData?.version) + const action = async (name, endpoint, expectedStatus) => { const response = await request(context, 'POST', `${path}/${endpoint}`, { expectedVersion: version, reason: context.marker }, { 'Idempotency-Key': `${context.marker}-${endpoint}` }); const result = context.apiSuccess(MODULE, name, response, '', OPTIONS); context.assert(MODULE, `${name} 状态返回`, response, result?.status === expectedStatus, `status=${result?.status || 'missing'}`, OPTIONS); version = Number(result?.version) } + for (const [name, endpoint, status] of [['提交预约','submit','PENDING_DISPATCH'],['派车','dispatch','DISPATCHED'],['开始提货','pickup','PICKUP_IN_PROGRESS'],['到仓','arrive','ARRIVED_WAREHOUSE'],['开始装货','load','LOADING'],['离场','depart','DEPARTED'],['完成','complete','COMPLETED']]) await action(name, endpoint, status) + const final = await request(context, 'GET', path); const finalData = data(final); context.apiSuccess(MODULE, '回查 COMPLETED 拖车预约', final, '', OPTIONS) + context.assert(MODULE, '拖车预约状态终态和费用快照正确', final, finalData?.status === 'COMPLETED' && finalData?.payableAmount != null && finalData?.receivableAmount != null, `status=${finalData?.status || 'missing'}`, OPTIONS) + const history = await request(context, 'GET', `${path}/history`); const histories = context.apiSuccess(MODULE, '查询拖车预约状态历史', history, '', OPTIONS) + const actions = Array.isArray(histories) ? histories.map((item) => item.action) : [] + context.assert(MODULE, '拖车状态历史动作、版本和审计操作者完整', history, ['SUBMIT','DISPATCH','PICKUP','ARRIVE','LOAD','DEPART','COMPLETE'].every((item) => actions.includes(item)) && histories.every((item) => Number.isFinite(Number(item.revision)) && Boolean(item.operatorName) && Boolean(item.createdAt)), `actions=${actions.join(',')}`, OPTIONS) }